blob: afd0752b37107531cefdbcf2c173c9f3feb94427 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "stdafx.h"
#include "UAccCOM2.h"
#include "MAccessible.h"
#include <algorithm>
#include "AccAction.h"
#include <com/sun/star/accessibility/XAccessibleText.hpp>
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
#include <com/sun/star/accessibility/XAccessibleImage.hpp>
#include <com/sun/star/accessibility/XAccessibleTable.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
#include <com/sun/star/accessibility/XAccessibleAction.hpp>
#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
#include <com/sun/star/accessibility/XAccessibleHyperText.hpp>
#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp>
#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/XAccessibleGroupPosition.hpp>
#include <com/sun/star/accessibility/XAccessibleValue.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
#include <com/sun/star/style/LineSpacing.hpp>
#include <com/sun/star/style/TabStop.hpp>
#include <com/sun/star/container/XIndexReplace.hpp>
#include "act.hxx"
using namespace com::sun::star::accessibility::AccessibleStateType;
// IA2 states mapping, and name
// maintenance the consistency, change one array, change the three all
long IA2_STATES[] =
{
IA2_STATE_ACTIVE, // = 0x1;
IA2_STATE_ARMED, // = 0x2;
IA2_STATE_DEFUNCT, // = 0x4;
IA2_STATE_EDITABLE, // = 0x8;
IA2_STATE_HORIZONTAL, // = 0x10;
IA2_STATE_ICONIFIED, // = 0x20;
IA2_STATE_INVALID_ENTRY, // = 0x80;
IA2_STATE_MANAGES_DESCENDANTS, // = 0x100;
IA2_STATE_MODAL, // = 0x200;
IA2_STATE_MULTI_LINE, // = 0x400;
IA2_STATE_OPAQUE, // = 0x800;
IA2_STATE_REQUIRED, // = 0x2000;
IA2_STATE_SELECTABLE_TEXT, // = 0x3000;
IA2_STATE_SINGLE_LINE, // = 0x4000;
IA2_STATE_STALE, // = 0x8000;
IA2_STATE_SUPPORTS_AUTOCOMPLETION, // = 0x10000;
IA2_STATE_TRANSIENT, //= 0x20000;
IA2_STATE_VERTICAL // = 0x40000;
};
/*
<=== map ===>
*/
short UNO_STATES[] =
{
ACTIVE, // = (sal_Int16)1;
ARMED, // = (sal_Int16)2;
DEFUNC, // = (sal_Int16)5;
EDITABLE, // = (sal_Int16)6;
HORIZONTAL, // = (sal_Int16)12;
ICONIFIED, // = (sal_Int16)13;
-1, //IA2_STATE_INVALID_ENTRY
MANAGES_DESCENDANTS, // = (sal_Int16)15;
MODAL, // = (sal_Int16)16;
MULTI_LINE, // = (sal_Int16)17;
OPAQUE, // = (sal_Int16)19;
-1, //IA2_STATE_REQUIRED
-1, //IA2_STATE_SELECTABLE_TEXT
SINGLE_LINE, // = (sal_Int16)26;
STALE, // = (sal_Int16)27;
-1, //IA2_STATE_SUPPORTS_AUTOCOMPLETION
TRANSIENT, //IA2_STATE_TRANSIENT
VERTICAL // = (sal_Int16)29;
};
// <=== map ===>
BSTR IA2_STATES_NAME[] =
{
_T("Active"),
_T("Armed"),
_T("Defunct"),
_T("Editable"),
_T("Horizontal"),
_T("Iconified"),
_T("Invalid Entry"),
_T("Manages Decendents"),
_T("Modal"),
_T("Multi Line"),
_T("Opaque"),
_T("Required"),
_T("Selectable Text"),
_T("Single Line"),
_T("Stale"),
_T("Supports Autocompletion"),
_T("Transient"),
_T("Vertical")
};
// IA2 states mapping, and name
// maintenance the consistency. change one, change them all
BSTR UNO_ALL_STATES[] =
{
_T("INVALID"), // INVALID ( 0 )
_T("ACTIVE"), // ACTIVE ( 1 )
_T("ARMED"), // ARMED ( 2 )
_T("BUSY"), // BUSY ( 3 )
_T("CHECKED"), // CHECKED ( 4 )
_T("DEFUNC"), // DEFUNC ( 5 )
_T("EDITABLE"), // EDITABLE ( 6 )
_T("ENABLED"), // ENABLED ( 7 )
_T("EXPANDABLE"), // EXPANDABLE ( 8 )
_T("EXPANDED"), // EXPANDED ( 9 )
_T("FOCUSABLE"), // FOCUSABLE ( 10 )
_T("FOCUSED"), // FOCUSED ( 11 )
_T("HORIZONTAL"), // HORIZONTAL ( 12 )
_T("ICONIFIED"), // ICONIFIED ( 13 )
_T("INDETERMINATE"), // INDETERMINATE ( 14 )
_T("MANAGES_DESCENDANTS"),// MANAGES_DESCENDANTS ( 15 )
_T("MODAL"), // MODAL ( 16 )
_T("MULTI_LINE"), // MULTI_LINE ( 17 )
_T("MULTI_SELECTABLE"), // MULTI_SELECTABLE ( 18 )
_T("OPAQUE"), // OPAQUE ( 19 )
_T("PRESSED"), // PRESSED ( 20 )
_T("RESIZABLE"), // RESIZABLE ( 21 )
_T("SELECTABLE"), // SELECTABLE ( 22 )
_T("SELECTED"), // SELECTED ( 23 )
_T("SENSITIVE"), // SENSITIVE ( 24 )
_T("SHOWING"), // SHOWING ( 25 )
_T("SINGLE_LINE"), // SINGLE_LINE ( 26 )
_T("STALE"), // STALE ( 27 )
_T("TRANSIENT"), // TRANSIENT ( 28 )
_T("VERTICAL"), // VERTICAL ( 29 )
_T("VISIBLE"), // VISIBLE ( 30 )
_T("MOVEABLE"), // MOVEABLE ( 31 )
_T("OFFSCREEN"), // OFFSCREEN ( 32 )
_T("COLLAPSE"), // COLLAPSE ( 33 )
_T("DEFAULT") // DEFAULT ( 34 )
};
using namespace com::sun::star::accessibility::AccessibleRole;
#define QUERYXINTERFACE(ainterface) \
{ \
if(pXAcc == NULL) \
return FALSE; \
pRContext = pXAcc->getAccessibleContext(); \
if( !pRContext.is() ) \
{ \
return FALSE; \
} \
Reference<X##ainterface> pRXI(pRContext,UNO_QUERY);\
if( !pRXI.is() ) \
{ \
return FALSE; \
} \
*ppXI = (XInterface*)pRXI.get(); \
return TRUE; \
}
#define ISDESTROY() \
if(m_isDestroy) \
return S_FALSE;
AccObjectManagerAgent* CMAccessible::g_pAgent = NULL;
CMAccessible::CMAccessible():
m_iRole(0x00),
m_dState(0x00),
m_dChildID(0x00),
m_dFocusChildID(UACC_NO_FOCUS),
m_hwnd(NULL),
m_pIParent(NULL),
m_pszName(NULL),
m_pszValue(NULL),
m_pszDescription(NULL),
m_isDestroy(FALSE),
m_pszActionDescription(NULL),
m_pXAction(NULL),
m_bRequiresSave(FALSE),
pUNOInterface(NULL)
{
m_sLocation.m_dLeft=0;
m_sLocation.m_dTop = 0;
m_sLocation.m_dWidth=0;
m_sLocation.m_dHeight=0;
CEnumVariant::Create(&m_pEnumVar);
m_containedObjects.clear();
}
CMAccessible::~CMAccessible()
{
if(m_pszName!=NULL)
{
SAFE_SYSFREESTRING(m_pszName);
m_pszName=NULL;
}
if(m_pszValue!=NULL)
{
SAFE_SYSFREESTRING(m_pszValue);
m_pszValue=NULL;
}
if(m_pszDescription!=NULL)
{
SAFE_SYSFREESTRING(m_pszDescription);
m_pszDescription=NULL;
}
if(m_pszActionDescription!=NULL)
{
SAFE_SYSFREESTRING(m_pszActionDescription);
m_pszActionDescription=NULL;
}
if(m_pIParent)
{
m_pIParent->Release();
m_pIParent=NULL;
}
pRef = NULL;
m_pEnumVar->Release();
m_containedObjects.clear();
pRContext = NULL;
}
/**
* Returns the Parent IAccessible interface pointer to AT.
* It should add reference, and the client should release the component.
* It should return E_FAIL when the parent point is null.
* @param ppdispParent [in,out] used to return the parent interface point.
* when the point is null, should return null.
* @return S_OK if successful and E_FAIL if the m_pIParent is NULL.
*/
STDMETHODIMP CMAccessible::get_accParent(IDispatch **ppdispParent)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(ppdispParent == NULL)
{
return E_INVALIDARG;
}
if(m_pIParent)
{
*ppdispParent = m_pIParent;
(*ppdispParent)->AddRef();
return S_OK;
}
else if(m_hwnd)
{
HRESULT hr = AccessibleObjectFromWindow(m_hwnd, OBJID_WINDOW, IID_IAccessible, (void**)ppdispParent);
if( ! SUCCEEDED( hr ) || ! ppdispParent )
{
return S_FALSE;
}
return S_OK;
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns child count of current COM object.
* @param pcountChildren [in,out] used to return the children count.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::get_accChildCount(long *pcountChildren)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pcountChildren == NULL)
{
return E_INVALIDARG;
}
if(!pUNOInterface)
return S_FALSE;
Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
if( pRContext.is() )
{
*pcountChildren = pRContext->getAccessibleChildCount();
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns child interface pointer for AT according to input child ID.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param ppdispChild, [in,out] use to return the child interface point.
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(ppdispChild == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
//get child interface pointer due to child ID
if(varChild.lVal==CHILDID_SELF)
{
AddRef();
*ppdispChild = this;
return S_OK;
}
*ppdispChild = GetChildInterface(varChild.lVal);
if((*ppdispChild) == NULL)
return E_FAIL;
(*ppdispChild)->AddRef();
return S_OK;
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the accessible name of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pszName, [in,out] use to return the name of the proper object.
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accName(VARIANT varChild, BSTR *pszName)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszName == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
if(varChild.lVal==CHILDID_SELF)
{
SAFE_SYSFREESTRING(*pszName);
*pszName = SysAllocString(m_pszName);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accName(varChild,pszName);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the accessible value of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pszValue, [in,out] use to return the value of the proper object.
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accValue(VARIANT varChild, BSTR *pszValue)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if( pszValue == NULL )
{
return E_INVALIDARG;
}
if( varChild.vt==VT_I4 )
{
if(varChild.lVal==CHILDID_SELF)
{
if(m_dState & STATE_SYSTEM_PROTECTED)
return E_ACCESSDENIED;
if ( m_pszValue !=NULL && wcslen(m_pszValue) == 0 )
return S_OK;
SAFE_SYSFREESTRING(*pszValue);
*pszValue = SysAllocString(m_pszValue);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accValue(varChild,pszValue);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the accessible description of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pszDescription, [in,out] use to return the description of the proper object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accDescription(VARIANT varChild, BSTR *pszDescription)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszDescription == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
if(varChild.lVal==CHILDID_SELF)
{
SAFE_SYSFREESTRING(*pszDescription);
*pszDescription = SysAllocString(m_pszDescription);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accDescription(varChild,pszDescription);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the accessible role of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pvarRole, [in,out] use to return the role of the proper object.
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarRole == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt == VT_I4)
{
if(varChild.lVal == CHILDID_SELF)
{
if( m_iRole < IA2_ROLE_CAPTION )
{
VariantInit(pvarRole);
pvarRole->vt = VT_I4;
pvarRole->lVal = m_iRole;
}
else
{
VariantInit(pvarRole);
pvarRole->vt = VT_I4;
pvarRole->lVal = ROLE_SYSTEM_CLIENT;
}
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accRole(varChild,pvarRole);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the accessible state of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pvarState, [in,out] use to return the state of the proper object.
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accState(VARIANT varChild, VARIANT *pvarState)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarState == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
if(varChild.lVal == CHILDID_SELF)
{
if(pUNOInterface)
{
Reference< XAccessibleContext > pContext = pUNOInterface->getAccessibleContext();
if(pContext.is())
{
// add the STATE_SYSTEM_LINKED state
Reference< XAccessibleHypertext > pRHypertext(pContext,UNO_QUERY);
if(pRHypertext.is())
{
if( pRHypertext->getHyperLinkCount() > 0 )
m_dState |= STATE_SYSTEM_LINKED;
else
m_dState &= ~STATE_SYSTEM_LINKED;
}
else
m_dState &= ~STATE_SYSTEM_LINKED;
}
}
VariantInit(pvarState);
pvarState->vt = VT_I4;
pvarState->lVal = m_dState;
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accState(varChild,pvarState);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the accessible helpString of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pszHelp, [in,out] use to return the helpString of the proper object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accHelp(VARIANT, BSTR *)
{
return E_NOTIMPL;
}
/**
* Returns the accessible HelpTopic of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pszHelpFile, [in,out] use to return the HelpTopic of the proper object.
* @param pidTopic, use to return the HelpTopic ID of the proper object.
* @return S_OK if successful and E_FAIL if failure.
* Not implemented yet
*/
STDMETHODIMP CMAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
{
return E_NOTIMPL;
}
static void GetMnemonicChar( const ::rtl::OUString& aStr, WCHAR* wStr)
{
int nLen = aStr.pData->length;
int i = 0;
WCHAR* text = aStr.pData->buffer;
while ( i < nLen )
{
if ( text[i] == L'~' )
if ( text[i+1] != L'~' )
{
wStr[0] = text[i+1];
break;
}
i++;
}
}
/**
* Returns the accessible keyboard shortcut of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pszKeyboardShortcut, [in,out] use to return the kbshortcut of the proper object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszKeyboardShortcut == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
if(varChild.lVal == CHILDID_SELF)
{
if( pUNOInterface )
{
Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
if( !pRContext.is() )
return S_FALSE;
Reference<XAccessibleAction> pRXI(pRContext,UNO_QUERY);
OLECHAR wString[64]={0};
if( pRXI.is() && pRXI->getAccessibleActionCount() >= 1)
{
Reference< XAccessibleKeyBinding > binding = pRXI->getAccessibleActionKeyBinding(0);
if( binding.is() )
{
long nCount = binding->getAccessibleKeyBindingCount();
if(nCount >= 1)
{
CAccAction::GetkeyBindingStrByXkeyBinding( binding->getAccessibleKeyBinding(0),wString );
}
}
}
if(wString[0] == 0)
{
Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
if(!pRrelationSet.is())
{
return S_FALSE;
}
long nRelCount = pRrelationSet->getRelationCount();
// Modified by Steve Yin, for SODC_1552
if( /*nRelCount <= 0 &&*/ m_iRole == ROLE_SYSTEM_TEXT )
{
VARIANT varParentRole;
VariantInit( &varParentRole );
m_pIParent->get_accRole(varChild, &varParentRole);
if( m_pIParent && varParentRole.lVal == ROLE_SYSTEM_COMBOBOX ) // edit in comoboBox
{
m_pIParent->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
return S_OK;
}
}
AccessibleRelation *paccRelation = NULL;
AccessibleRelation accRelation;
for(int i=0; i<nRelCount ; i++)
{
if( pRrelationSet->getRelation(i).RelationType == 6 )
{
accRelation = pRrelationSet->getRelation(i);
paccRelation = &accRelation;
}
}
if(paccRelation == NULL)
return S_FALSE;
Sequence< Reference< XInterface > > xTargets = paccRelation->TargetSet;
Reference<XInterface> pRAcc = xTargets[0];
XAccessible* pXAcc = (XAccessible*)pRAcc.get();
Reference<XAccessibleContext> pRLebelContext = pXAcc->getAccessibleContext();
if(!pRLebelContext.is())
return S_FALSE;
pRrelationSet = pRLebelContext->getAccessibleRelationSet();
nRelCount = pRrelationSet->getRelationCount();
paccRelation = NULL;
for(int j=0; j<nRelCount ; j++)
{
if( pRrelationSet->getRelation(j).RelationType == 5 )
{
accRelation = pRrelationSet->getRelation(j);
paccRelation = &accRelation;
}
}
if(paccRelation)
{
xTargets = paccRelation->TargetSet;
pRAcc = xTargets[0];
if(pUNOInterface != (XAccessible*)pRAcc.get())
return S_FALSE;
}
Reference<XAccessibleExtendedComponent> pRXIE(pRLebelContext,UNO_QUERY);
if(!pRXIE.is())
return S_FALSE;
::rtl::OUString ouStr = pRXIE->getTitledBorderText();
WCHAR key[2] = {NULL};
GetMnemonicChar(ouStr, key);
if(key[0] != 0)
{
wcscat(wString, L"Alt+");
wcscat(wString, key);
}
else
return S_FALSE;
}
SAFE_SYSFREESTRING(*pszKeyboardShortcut);
*pszKeyboardShortcut = SysAllocString(wString);
return S_OK;
}
else
{
return S_FALSE;
}
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accKeyboardShortcut(varChild,pszKeyboardShortcut);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the current focused child to AT.
* @param pvarChild, [in,out] vt member of pvarChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accFocus(VARIANT *pvarChild)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarChild == NULL)
{
return E_INVALIDARG;
}
if( m_dFocusChildID==UACC_NO_FOCUS )
{
pvarChild->vt = VT_EMPTY;//no focus on the object and its children
return S_OK;
}
//if the descendant of current object has focus indicated by m_dFocusChildID, return the IDispatch of this focused object
else
{
IMAccessible* pIMAcc = NULL;
g_pAgent->GetIAccessibleFromResID(m_dFocusChildID,&pIMAcc);
pIMAcc->AddRef();
pvarChild->vt = VT_DISPATCH;
pvarChild->pdispVal = pIMAcc;
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the selection of the current COM object to AT.
* @param pvarChildren,[in,out]
* if selection num is 0,return VT_EMPTY for vt,
* if selection num is 1,return VT_I4 for vt,and child index for lVal
* if selection num >1,return VT_UNKNOWN for vt, and IEnumVariant* for punkVal
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accSelection(VARIANT *pvarChildren)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarChildren == NULL)
{
return E_INVALIDARG;
}
switch(m_pEnumVar->GetCountOfElements())
{
case 0:
pvarChildren->vt = VT_EMPTY;
break;
case 1:
VARIANT varTmp[1];
ULONG count;
VariantInit(&varTmp[0]);
m_pEnumVar->Next(1,varTmp,&count);
if(count!=1)
return S_FALSE;
pvarChildren->vt = VT_I4;
pvarChildren->lVal = varTmp[0].lVal;
VariantClear(&varTmp[0]);
m_pEnumVar->Reset();
break;
default:
pvarChildren->vt = VT_UNKNOWN;
m_pEnumVar->AddRef();
pvarChildren->punkVal = m_pEnumVar;
break;
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the location of the current COM object self or its one child to AT.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param pxLeft, [in,out] use to return the x-coordination of the proper object.
* @param pyTop, [in,out] use to return the y-coordination of the proper object.
* @param pcxWidth, [in,out] use to return the x-coordination width of the proper object.
* @param pcyHeight, [in,out] use to return the y-coordination height of the proper object.
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pxLeft == NULL || pyTop == NULL || pcxWidth == NULL || pcyHeight == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
if(varChild.lVal==CHILDID_SELF)
{
if(pUNOInterface)
{
Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
if( !pRContext.is() )
return S_FALSE;
Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY);
if( !pRComponent.is() )
return S_FALSE;
::com::sun::star::awt::Point pCPoint = pRComponent->getLocationOnScreen();
::com::sun::star::awt::Size pCSize = pRComponent->getSize();
*pxLeft = pCPoint.X;
*pyTop = pCPoint.Y;
*pcxWidth = pCSize.Width;
*pcyHeight = pCSize.Height;
return S_OK;
}
else
{
*pxLeft = m_sLocation.m_dLeft;
*pyTop = m_sLocation.m_dTop;
*pcxWidth = m_sLocation.m_dWidth;
*pcyHeight = m_sLocation.m_dHeight;
return S_OK;
}
}
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Returns the current focused child to AT.
* @param navDir, the direction flag of the navigation.
* @param varStart, the start child id of this navigation action.
* @param pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarEndUpAt == NULL)
{
return E_INVALIDARG;
}
HRESULT ret = E_FAIL;
switch (navDir)
{
case NAVDIR_FIRSTCHILD:
ret = GetFirstChild(varStart,pvarEndUpAt);
break;
case NAVDIR_LASTCHILD:
ret = GetLastChild(varStart,pvarEndUpAt);
break;
case NAVDIR_NEXT:
ret = GetNextSibling(varStart,pvarEndUpAt);
break;
case NAVDIR_PREVIOUS:
ret = GetPreSibling(varStart,pvarEndUpAt);
break;
case NAVDIR_DOWN://do not implement temporarily
break;
case NAVDIR_UP://do not implement temporarily
break;
case NAVDIR_LEFT://do not implement temporarily
break;
case NAVDIR_RIGHT://do not implement temporarily
break;
default:
break;
};
return ret;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarChild)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarChild == NULL)
{
return E_INVALIDARG;
}
long x, y, w, h;
VARIANT varSelf;
VariantInit(&varSelf);
varSelf.vt = VT_I4;
varSelf.lVal = CHILDID_SELF;
accLocation(&x,&y,&w,&h,varSelf);
if( (x < xLeft && (x + w) >xLeft) && (y < yTop && (y + h) >yTop) )
{
int i, nCount;
pvarChild->vt = VT_EMPTY;
Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
nCount = pRContext->getAccessibleChildCount();
if(nCount > 256)
return E_FAIL;
IMAccessible* child = NULL;
for( i = 0; i<nCount; i++)
{
child = GetChildInterface(i + 1);
if(child && child->accHitTest(xLeft,yTop,pvarChild) == S_OK)
break;
}
if(pvarChild->vt == VT_DISPATCH)
return S_OK;
if( i < nCount)
{
pvarChild->vt = VT_DISPATCH;
pvarChild->pdispVal = child;
child->AddRef();
}
else
{
pvarChild->vt = VT_I4;
pvarChild->lVal = CHILDID_SELF;
}
return S_OK;
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* Get The other Interface from CMAccessible.
* @param guidService, must be IID_IAccessible here.
* @param riid, the IID interface .
* @return S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::QueryService(REFGUID guidService, REFIID riid, void** ppvObject)
{
if( InlineIsEqualGUID(guidService, IID_IAccessible) )
return QueryInterface(riid, ppvObject);
return S_FALSE;
}
/**
* Set the accessible name of the current COM object self or its one child from UNO.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param szName, the name used to set the name of the proper object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::put_accName(VARIANT varChild, BSTR szName)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(varChild.vt==VT_I4)
{
if(varChild.lVal==CHILDID_SELF)
{
SAFE_SYSFREESTRING(m_pszName);
m_pszName=SysAllocString(szName);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->put_accName(varChild,szName);
}
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
/**
* Set the accessible value of the current COM object self or its one child from UNO.
* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param szValue, the value used to set the value of the proper object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::put_accValue(VARIANT varChild, BSTR szValue)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(varChild.vt==VT_I4)
{
if(varChild.lVal==CHILDID_SELF)
{
SysAllocString(m_pszValue);
m_pszValue=SysAllocString(szValue);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->put_accValue(varChild,szValue);
}
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
/**
* Set the accessible name of the current COM object self from UNO.
* @param pszName, the name value used to set the name of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccName(const OLECHAR __RPC_FAR *pszName)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszName == NULL)
{
return E_INVALIDARG;
}
SAFE_SYSFREESTRING(m_pszName);//??
m_pszName = SysAllocString(pszName);
if(m_pszName==NULL)
return E_FAIL;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Set the accessible role of the current COM object self from UNO.
* @param pRole, the role value used to set the role of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccRole(unsigned short pRole)
{
m_iRole = pRole;
return S_OK;
}
/**
* Add one state into the current state set for the current COM object from UNO.
* @param pXSate, the state used to set the name of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::DecreaseState(DWORD pXSate)
{
m_dState &= (~pXSate);
return S_OK;
}
/**
* Delete one state into the current state set for the current COM object from UNO.
* @param pXSate, the state used to set the name of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::IncreaseState(DWORD pXSate)
{
m_dState |= pXSate;
return S_OK;
}
/**
* Set state into the current state set for the current COM object from UNO.
* @param pXSate, the state used to set the name of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::SetState(DWORD pXSate)
{
m_dState = pXSate;
return S_OK;
}
/**
* Set the accessible description of the current COM object self from UNO.
* @param pszDescription, the name used to set the description of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccDescription(const OLECHAR __RPC_FAR *pszDescription)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszDescription == NULL)
{
return E_INVALIDARG;
}
SAFE_SYSFREESTRING(m_pszDescription);
m_pszDescription = SysAllocString(pszDescription);
if(m_pszDescription==NULL)
return E_FAIL;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Set the accessible value of the current COM object self from UNO.
* @param pszAccValue, the name used to set the value of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccValue(const OLECHAR __RPC_FAR *pszAccValue)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszAccValue == NULL)
{
return E_INVALIDARG;
}
SAFE_SYSFREESTRING(m_pszValue);
m_pszValue = SysAllocString(pszAccValue);
if(m_pszValue==NULL)
return E_FAIL;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Set the HWND value of the current COM object self from UNO. It should set the parent IAccessible
* Object through the method AccessibleObjectFromWindow(...).
* @param hwnd, the HWND used to set the value of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccWindowHandle(HWND hwnd)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
m_hwnd = hwnd;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Set accessible focus by specifying child ID
* @param dChildID, the child id identifies the focus child.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccFocus(long dChildID)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(dChildID==CHILDID_SELF)
{
if(m_pIParent)
{
m_pIParent->Put_XAccFocus(m_dChildID);
}
}
else
{
m_dFocusChildID = dChildID;
//traverse all ancestors to set the focused child ID so that when the get_accFocus is called on
//any of the ancestors, this id can be used to get the IAccessible of focused object.
if(m_pIParent)
{
m_pIParent->Put_XAccFocus(dChildID);
}
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
*Set accessible object location for the current COM object
* @param sLocation, the location of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccLocation(const Location sLocation)
{
this->m_sLocation = sLocation;
return S_OK;
}
/**
* Set accessible parent object for the current COM object if
* the current object is a child of some COM object
* @param pIParent, the parent of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccParent(IMAccessible __RPC_FAR *pIParent)
{
this->m_pIParent = pIParent;
if(pIParent)
m_pIParent->AddRef();
return S_OK;
}
/**
* Set unique child id to COM
* @param dChildID, the id of the current object.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccChildID(long dChildID)
{
this->m_dChildID = dChildID;
return S_OK;
}
/**
* Set AccObjectManagerAgent object pointer to COM
* @param pAgent, the AccObjectManagerAgent point.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccAgent(long pAgent)
{
g_pAgent = (AccObjectManagerAgent*)pAgent;
return S_OK;
}
/**
* When a UNO control disposing, it disposes its listeners,
* then notify AccObject in bridge management, then notify
* COM that the XAccessible is invalid,so set pUNOInterface as NULL
* @param isDestroy, true is it need to be destroyed.
* @return S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::NotifyDestroy(BOOL isDestroy)
{
m_isDestroy = isDestroy;
pUNOInterface = NULL;
return S_OK;
}
/**
*private methods that help implement public functions
*/
/**
* Return child interface pointer by child ID,note: need to call AddRef()
* @param lChildID, specify child index,which AT(such as Inspect32) gives.
* @return IMAccessible*, pointer to the corresponding child object.
*/
IMAccessible* CMAccessible::GetChildInterface(long dChildID)//for test
{
long dChildIndex = 0;
if(dChildID<0)
{
if(g_pAgent)
{
IMAccessible* pIMAcc = NULL;
g_pAgent->GetIAccessibleFromResID(dChildID,&pIMAcc);
return pIMAcc;
}
return NULL;
}
else
{
Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
if( !pRContext.is() )
return NULL;
if(dChildID<1 || dChildID>pRContext->getAccessibleChildCount())
return NULL;
IAccessible* pChild = NULL;
Reference< XAccessible > pXChild = pRContext->getAccessibleChild(dChildID-1);
BOOL isGet = get_IAccessibleFromXAccessible((long)pXChild.get(),&pChild);
if(!isGet)
{
g_pAgent->InsertAccObj(pXChild.get(),pUNOInterface,(long)m_hwnd);
isGet = get_IAccessibleFromXAccessible((long)pXChild.get(),&pChild);
}
if(isGet)
{
IMAccessible* pIMAcc = (IMAccessible*)pChild;
return pIMAcc;
}
}
return NULL;
}
/**
* For List, tree and table,these roles belong to manage_decendant in UNO,
* need to process specifically when navigate
* @return BOOL, if it is decendantmanager, return true.
*/
BOOL CMAccessible::IsDecendantManage()
{
return (m_iRole==ROLE_SYSTEM_LIST)||(m_iRole==ROLE_SYSTEM_OUTLINE)||(m_iRole==ROLE_SYSTEM_TABLE);
}
/**
* for decendantmanager circumstance,provide child interface when navigate
* @param varCur, the current child.
* @param flags, the navigation direction.
* @return IMAccessible*, the child of the end up node.
*/
IMAccessible* CMAccessible::GetNavigateChildForDM(VARIANT varCur, short flags)
{
XAccessibleContext* pXContext = GetContextByXAcc(pUNOInterface);
if(pXContext==NULL)
{
return NULL;
}
int count = pXContext->getAccessibleChildCount();
if(count<1)
{
return NULL;
}
IMAccessible* pCurChild = NULL;
XAccessible* pChildXAcc = NULL;
Reference<XAccessible> pRChildXAcc;
XAccessibleContext* pChildContext = NULL;
int index = 0,delta=0;
switch(flags)
{
case DM_FIRSTCHILD:
pRChildXAcc = pXContext->getAccessibleChild(0);
break;
case DM_LASTCHILD:
pRChildXAcc = pXContext->getAccessibleChild(count-1);
break;
case DM_NEXTCHILD:
case DM_PREVCHILD:
pCurChild = GetChildInterface(varCur.lVal);
if(pCurChild==NULL)
{
return NULL;
}
pCurChild->GetUNOInterface((long*)&pChildXAcc);
if(pChildXAcc==NULL)
{
return NULL;
}
pChildContext = GetContextByXAcc(pChildXAcc);
if(pChildContext == NULL)
{
return NULL;
}
delta = (flags==DM_NEXTCHILD)?1:-1;
//currently, getAccessibleIndexInParent is error in UNO for
//some kind of List,such as ValueSet, the index will be less 1 than
//what should be, need to fix UNO code
index = pChildContext->getAccessibleIndexInParent()+delta;
if((index>=0)&&(index<=count-1))
{
pRChildXAcc = pXContext->getAccessibleChild(index);
}
break;
default:
break;
}
if(!pRChildXAcc.is())
{
return NULL;
}
pChildXAcc = pRChildXAcc.get();
g_pAgent->InsertAccObj(pChildXAcc,pUNOInterface);
return g_pAgent->GetIMAccByXAcc(pChildXAcc);
}
/**
*the following 4 private methods are for accNavigate implementation
*/
/**
* Return first child for parent container, process differently according
* to whether it is decendant manage
* @param varStart, the start child id of this navigation action.
* @param pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetFirstChild(VARIANT varStart,VARIANT* pvarEndUpAt)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarEndUpAt == NULL)
{
return E_INVALIDARG;
}
if(varStart.vt != VT_I4)
{
pvarEndUpAt->vt = VT_EMPTY;
return E_INVALIDARG;
}
pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_FIRSTCHILD);
if(pvarEndUpAt->pdispVal)
{
pvarEndUpAt->pdispVal->AddRef();
pvarEndUpAt->vt = VT_DISPATCH;
return S_OK;
}
pvarEndUpAt->vt = VT_EMPTY;
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
/**
* Return last child for parent container, process differently according
* to whether it is decendant manage
* @param varStart, the start child id of this navigation action.
* @param pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetLastChild(VARIANT varStart,VARIANT* pvarEndUpAt)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarEndUpAt == NULL)
{
return E_INVALIDARG;
}
if(varStart.vt != VT_I4)
{
pvarEndUpAt->vt = VT_EMPTY;
return E_INVALIDARG;
}
pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_LASTCHILD);
if(pvarEndUpAt->pdispVal)
{
pvarEndUpAt->pdispVal->AddRef();
pvarEndUpAt->vt = VT_DISPATCH;
return S_OK;
}
pvarEndUpAt->vt = VT_EMPTY;
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
/**
* The method GetNextSibling is general, whatever it is decendant manage or not
* Get the next sibling object.
* @param varStart, the start child id of this navigation action.
* @param pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetNextSibling(VARIANT varStart,VARIANT* pvarEndUpAt)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(varStart.vt != VT_I4)
{
pvarEndUpAt->vt = VT_EMPTY;
return E_INVALIDARG;
}
Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
if(pRContext.is())
{
varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent() + 2);
if(m_pIParent)
if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK)
{
pvarEndUpAt->vt = VT_DISPATCH;
return S_OK;
}
}
pvarEndUpAt->vt = VT_EMPTY;
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
/**
*the method GetPreSibling is general, whatever it is decendant manage or not
* @param varStart, the start child id of this navigation action.
* @param pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetPreSibling(VARIANT varStart,VARIANT* pvarEndUpAt)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pvarEndUpAt == NULL)
{
return E_INVALIDARG;
}
if(varStart.vt != VT_I4)
{
pvarEndUpAt->vt = VT_EMPTY;
return E_INVALIDARG;
}
Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
if(pRContext.is())
{
varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent());
if(m_pIParent && varStart.iVal > 0)
if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK)
{
pvarEndUpAt->vt = VT_DISPATCH;
return S_OK;
}
}
pvarEndUpAt->vt = VT_EMPTY;
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
/**
* For IAccessible2 implementation methods
*/
STDMETHODIMP CMAccessible::get_nRelations( long __RPC_FAR *nRelations)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(nRelations == NULL)
{
return E_INVALIDARG;
}
*nRelations = 0;
if( !pRContext.is() )
return E_FAIL;
Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
if(!pRrelationSet.is())
{
*nRelations = 0;
return S_OK;
}
*nRelations = pRrelationSet->getRelationCount();
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible::get_relation( long relationIndex, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(relation == NULL)
{
return E_INVALIDARG;
}
if( !pRContext.is() )
return E_FAIL;
long nMax = 0;
long nReal = 0;
get_nRelations(&nMax);
*relation = (IAccessibleRelation*)::CoTaskMemAlloc(sizeof(IAccessibleRelation));
// #CHECK Memory Allocation#
if(*relation == NULL)
{
return E_FAIL;
}
if( relationIndex < nMax )
{
Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
if(!pRrelationSet.is())
{
return E_FAIL;
}
IAccessibleRelation* pRelation = NULL;
ActivateActContext();
HRESULT hr = CoCreateInstance( CLSID_AccRelation, NULL, CLSCTX_SERVER ,
IID_IAccessibleRelation,
(void **)&pRelation);
DeactivateActContext();
if(SUCCEEDED(hr))
{
IUNOXWrapper* wrapper = NULL;
hr = pRelation->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
if(SUCCEEDED(hr))
{
AccessibleRelation accRelation = pRrelationSet->getRelation(relationIndex);
wrapper->put_XSubInterface((long)&accRelation);
wrapper->Release();
*relation = pRelation;
return S_OK;
}
}
}
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible::get_relations( long, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation, long __RPC_FAR *nRelations)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(relation == NULL || nRelations == NULL)
{
return E_INVALIDARG;
}
// #CHECK XInterface#
if( !pRContext.is() )
return E_FAIL;
Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
if(!pRrelationSet.is())
{
*nRelations = 0;
return S_OK;
}
long nCount = pRrelationSet->getRelationCount();
*relation = (IAccessibleRelation*)::CoTaskMemAlloc(nCount*sizeof(IAccessibleRelation));
// #CHECK Memory Allocation#
if(*relation == NULL)
{
return E_FAIL;
}
for(int i=0; i<nCount ; i++)
{
IAccessibleRelation* pRelation = NULL;
ActivateActContext();
HRESULT hr = CoCreateInstance( CLSID_AccRelation, NULL, CLSCTX_SERVER ,
IID_IAccessibleRelation,
(void **)&pRelation);
DeactivateActContext();
if(SUCCEEDED(hr))
{
IUNOXWrapper* wrapper = NULL;
hr = pRelation->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
if(SUCCEEDED(hr))
{
AccessibleRelation accRelation = pRrelationSet->getRelation(i);
wrapper->put_XSubInterface((long)&accRelation);
wrapper->Release();
}
(relation)[i] = pRelation;
}
}
*nRelations = nCount;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible::role(long __RPC_FAR *role)
{
ENTER_PROTECTED_BLOCK
(*role) = m_iRole;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_nActions(long __RPC_FAR *nActions)
{
try
{
ISDESTROY()
// #CHECK#
if(nActions == NULL)
{
return E_INVALIDARG;
}
*nActions = 0L;
IAccessibleAction* pAcc = NULL;
HRESULT hr = QueryInterface(IID_IAccessibleAction, (void**)&pAcc);
if( hr == S_OK )
{
pAcc->nActions(nActions);
pAcc->Release();
}
return S_OK;
}
catch(...)
{
*nActions = 0L;
return S_OK;
}
}
STDMETHODIMP CMAccessible:: scrollToPoint(enum IA2CoordinateType, long, long)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: scrollTo(enum IA2ScrollType)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
static XAccessible* getTheParentOfMember(XAccessible* pXAcc)
{
// #CHECK#
if(pXAcc == NULL)
{
return NULL;
}
Reference<XAccessibleContext> pRContext = pXAcc->getAccessibleContext();
Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
long nRelations = pRrelationSet->getRelationCount();
for(int i=0 ; i<nRelations ; i++)
{
AccessibleRelation accRelation = pRrelationSet->getRelation(i);
if(accRelation.RelationType == 7)
{
Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet;
return (XAccessible*)xTargets[0].get();
}
}
return NULL;
}
STDMETHODIMP CMAccessible:: get_groupPosition(long __RPC_FAR *groupLevel,long __RPC_FAR *similarItemsInGroup,long __RPC_FAR *positionInGroup)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(groupLevel == NULL || similarItemsInGroup == NULL || positionInGroup == NULL)
{
return E_INVALIDARG;
}
Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
if(!pRContext.is())
return E_FAIL;
long Role = pRContext->getAccessibleRole();
*groupLevel = 0;
*similarItemsInGroup = 0;
*positionInGroup = 0;
if (Role != AccessibleRole::DOCUMENT)
{
Reference< XAccessibleGroupPosition > xGroupPosition( pRContext, UNO_QUERY );
if ( xGroupPosition.is() )
{
Sequence< sal_Int32 > rSeq = xGroupPosition->getGroupPosition( makeAny( pRContext ) );
sal_Int32* pSeq = rSeq.getArray();
if ( pSeq )
{
*groupLevel = pSeq[0];
*similarItemsInGroup = pSeq[1];
*positionInGroup = pSeq[2];
return S_OK;
}
return S_OK;
}
}
Reference< XAccessible> pParentAcc = pRContext->getAccessibleParent();
if( !pParentAcc.is() )
{
return S_OK;
}
Reference<XAccessibleContext> pRParentContext = pParentAcc->getAccessibleContext();
int level = 0;
int index = 0;
int number = 0;
if( Role == RADIO_BUTTON )
{
Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
long nRel = pRrelationSet->getRelationCount();
for(int i=0 ; i<nRel ; i++)
{
AccessibleRelation accRelation = pRrelationSet->getRelation(i);
if(accRelation.RelationType == 7)
{
Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet;
int nCount = xTargets.getLength();
Reference<XInterface> pRAcc = xTargets[0];
for(int j=0; j<pRParentContext->getAccessibleChildCount(); j++)
{
if( getTheParentOfMember(pRParentContext->getAccessibleChild(j).get())
== (XAccessible*)pRAcc.get() &&
pRParentContext->getAccessibleChild(j)->getAccessibleContext()->getAccessibleRole() == RADIO_BUTTON)
number++;
if(pRParentContext->getAccessibleChild(j).get() == pUNOInterface)
index = number;
}
}
}
*groupLevel = 1;
*similarItemsInGroup = number;
*positionInGroup = index;
return S_OK;
}
else if ( COMBO_BOX == Role )
{
*groupLevel = 1;
*similarItemsInGroup = 0;
*positionInGroup = -1;
long nCount = pRContext->getAccessibleChildCount();
if( 2 != nCount)
{
return S_OK;
}
Reference<XAccessible> xList=pRContext->getAccessibleChild(1);
if (!xList.is())
{
return S_OK;
}
Reference<XAccessibleContext> xListContext(xList,UNO_QUERY);
if (!xListContext.is())
{
return S_OK;
}
Reference<XAccessibleSelection> xListSel(xList,UNO_QUERY);
if (!xListSel.is())
{
return S_OK;
}
*similarItemsInGroup = xListContext->getAccessibleChildCount();
if (*similarItemsInGroup > 0 )
{
try
{
Reference<XAccessible> xChild = xListSel->getSelectedAccessibleChild(0);
if (xChild.is())
{
Reference<XAccessibleContext> xChildContext(xChild,UNO_QUERY);
if (xChildContext.is())
{
*positionInGroup=xChildContext->getAccessibleIndexInParent() + 1 ;
return S_OK;
}
}
}
catch(...)
{}
}
return S_OK;
}
else if ( PAGE_TAB == Role )
{
*groupLevel = 1;
*similarItemsInGroup = pRParentContext->getAccessibleChildCount();
if (*similarItemsInGroup > 0 )
{
*positionInGroup=pRContext->getAccessibleIndexInParent() + 1 ;
}
else
{
*positionInGroup = -1;
}
return S_OK;
}
BOOL isFound = FALSE;
while( pParentAcc.is() && !isFound)
{
level++;
pRParentContext = pParentAcc->getAccessibleContext();
Role = pRParentContext->getAccessibleRole();
if( (Role == TREE) || (Role == LIST) )
isFound = TRUE;
pParentAcc = pRParentContext->getAccessibleParent();
}
if( isFound )
{
Reference< XAccessible> pTempAcc = pRContext->getAccessibleParent();
pRParentContext = pTempAcc->getAccessibleContext();
*groupLevel = level;
*similarItemsInGroup = pRParentContext->getAccessibleChildCount();
*positionInGroup = pRContext->getAccessibleIndexInParent() + 1;
}
else
{
*groupLevel = 0;
*similarItemsInGroup = 0;
*positionInGroup = 0;
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_extendedStates( long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_uniqueID(long __RPC_FAR *uniqueID)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(uniqueID == NULL)
{
return E_INVALIDARG;
}
*uniqueID = m_dChildID;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_windowHandle(HWND __RPC_FAR *windowHandle)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(windowHandle == NULL)
{
return E_INVALIDARG;
}
HWND nHwnd = m_hwnd;
IAccessible* pParent = m_pIParent;
CMAccessible* pChild = this;
while((nHwnd==0) && pParent)
{
pChild = (CMAccessible*)pParent;
if(pChild)
{
pParent = (IAccessible*)pChild->m_pIParent;
nHwnd = (HWND)pChild->m_hwnd;
}
else
pParent = NULL;
}
*windowHandle = nHwnd;
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Get XAccessibleContext directly from UNO by the stored XAccessible pointer
* @param pXAcc, UNO XAccessible object point.
* @return XAccessibleContext*, the context of the pXAcc.
*/
XAccessibleContext* CMAccessible::GetContextByXAcc( XAccessible* pXAcc )
{
Reference< XAccessibleContext > pRContext;
if( pXAcc == NULL)
return NULL;
pRContext = pXAcc->getAccessibleContext();
if( !pRContext.is() )
return NULL;
return pRContext.get();
}
/**
* Return the member variable m_pXAccessibleSelection, instead of
* get XAccessibleSelection according to XAccessibleContext because if so,it will
* depend on the UNO implementation code,so when COM is created, put XAccessibleSelection
* by bridge management system
* @return XAccessibleSelection*, the selection of the current object.
*/
Reference< XAccessibleSelection > CMAccessible::GetSelection()
{
if( pUNOInterface == NULL )
return NULL;
Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
if(pRContext.is())
{
Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY);
return pRSelection;
}
return NULL;
}
/**
* Select one XAccessible item, for accSelect implementation
* @param pItem, the item should be selected.
* @return S_OK if successful.
*/
HRESULT CMAccessible::SelectChild(XAccessible* pItem)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
XAccessibleContext* pParentContext = GetContextByXAcc( pUNOInterface );
XAccessibleContext* pContext = GetContextByXAcc( pItem );
if( pParentContext == NULL || pContext == NULL )
return E_FAIL;
Reference< XAccessibleSelection > pRSelection = GetSelection();
if( !pRSelection.is() )
return E_FAIL;
long Index = pContext->getAccessibleIndexInParent();
pRSelection->selectAccessibleChild( Index );
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Deselect one XAccessible item, for accSelect implimentation
* @param pItem, the item should be deselected.
* @return S_OK if successful.
*/
HRESULT CMAccessible::DeSelectChild(XAccessible* pItem)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
XAccessibleContext* pParentContext = GetContextByXAcc( pUNOInterface );
;
XAccessibleContext* pContext = GetContextByXAcc( pItem );
if( pParentContext == NULL || pContext == NULL )
return E_INVALIDARG;
Reference< XAccessibleSelection > pRSelection = GetSelection();
if( !pRSelection.is() )
return E_FAIL;
long Index = pContext->getAccessibleIndexInParent();
pRSelection->deselectAccessibleChild( Index );
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Select multiple XAccessible items,for implementation of accSelect
* @param pItem, the items should be selected.
* @param size, the size of the items.
* @return S_OK if successful.
*/
HRESULT CMAccessible::SelectMutipleChidren( XAccessible** pItem,int size )
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pItem == NULL)
{
return E_INVALIDARG;
}
for(int index = 0;index < size;index++)
{
SelectChild( pItem[index] );
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Deselect multiple XAccessible items,for implementation of accSelect
* @param pItem, the items should be selected.
* @param size, the size of the items.
* @return S_OK if successful.
*/
HRESULT CMAccessible::DeSelectMutipleChildren( XAccessible** pItem,int size )
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pItem == NULL)
{
return E_INVALIDARG;
}
for(int index = 0;index < size;index++)
{
DeSelectChild( pItem[index] );
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* When COM is created, UNO set XAccessible pointer to it
* in order to COM can operate UNO information
* @param pXAcc, the XAccessible object of current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::SetXAccessible(long pXAcc)
{
pUNOInterface = (XAccessible*)pXAcc;
pRef = pUNOInterface;
m_pEnumVar->PutSelection(/*XAccessibleSelection*/(long)pUNOInterface);
pRContext = pUNOInterface->getAccessibleContext();
pRContextInterface = (XAccessibleContext*)pRContext.is();
return S_OK;
}
/**
* accSelect method has many optional flags, needs to process comprehensively
* Mozilla and Microsoft do not implement SELFLAG_EXTENDSELECTION flag.
* The implementation of this flag is a little trouble-shooting,so we also
* do not implement it now
* @param flagsSelect, the selection flag of the select action.
* @param varChild, the child object pointer of current action.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::accSelect(long flagsSelect, VARIANT varChild)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
if( (flagsSelect&SELFLAG_ADDSELECTION) &&
(SELFLAG_REMOVESELECTION&flagsSelect) )
return E_INVALIDARG;
if ( (flagsSelect&SELFLAG_TAKESELECTION) &&
(
(flagsSelect&SELFLAG_ADDSELECTION) ||
(flagsSelect&SELFLAG_REMOVESELECTION) ||
(flagsSelect&SELFLAG_EXTENDSELECTION )
)
)
return E_INVALIDARG;
if ( varChild.vt != VT_I4 )
return E_INVALIDARG;
IMAccessible* pSelectAcc;
if( varChild.lVal == CHILDID_SELF )
{
pSelectAcc = this;
pSelectAcc->AddRef();
}
else
{
pSelectAcc = GetChildInterface(varChild.lVal);
}
if( pSelectAcc == NULL )
return E_INVALIDARG;
if( flagsSelect&SELFLAG_TAKEFOCUS )
{
long pTempUNO = 0;
pSelectAcc->GetUNOInterface( &pTempUNO);
if( pTempUNO == NULL )
return NULL;
Reference< XAccessibleContext > pRContext = ( (XAccessible*)pTempUNO)->getAccessibleContext();
Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY);
Reference< XAccessible > pRParentXAcc = pRContext->getAccessibleParent();
Reference< XAccessibleContext > pRParentContext = pRParentXAcc->getAccessibleContext();
Reference< XAccessibleComponent > pRParentComponent(pRParentContext,UNO_QUERY);
Reference< XAccessibleSelection > pRParentSelection(pRParentContext,UNO_QUERY);
pRComponent->grabFocus();
if( flagsSelect & SELFLAG_TAKESELECTION )
{
pRParentSelection->clearAccessibleSelection();
pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() );
}
if( flagsSelect & SELFLAG_ADDSELECTION )
{
pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() );
}
if( flagsSelect & SELFLAG_REMOVESELECTION )
{
pRParentSelection->deselectAccessibleChild( pRContext->getAccessibleIndexInParent() );
}
if( flagsSelect & SELFLAG_EXTENDSELECTION )
{
long indexInParrent = pRContext->getAccessibleIndexInParent();
if( pRParentSelection->isAccessibleChildSelected( indexInParrent + 1 ) ||
pRParentSelection->isAccessibleChildSelected( indexInParrent - 1 ) )
{
pRParentSelection->selectAccessibleChild( indexInParrent );
}
}
}
pSelectAcc->Release();
return S_OK;
LEAVE_PROTECTED_BLOCK
}
/**
* Return XAccessible interface pointer when needed
* @param pXAcc, [in, out] the Uno interface of the current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::GetUNOInterface(long* pXAcc)
{
// #CHECK#
if(pXAcc == NULL)
return E_INVALIDARG;
*pXAcc = (long)pUNOInterface;
return S_OK;
}
/**
* Helper method for Implementation of get_accDefaultAction
* @param pAction, the default action point of the current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::SetDefaultAction(long pAction)
{
m_pXAction = (XAccessibleAction*)pAction;
return S_OK;
}
/**
* This method is called when AT open some UI elements initially
* the UI element takes the default action defined here
* @param varChild, the child id of the defaultaction.
* @param pszDefaultAction,[in/out] the description of the current action.
* @return S_OK if successful.
*/
HRESULT STDMETHODCALLTYPE CMAccessible::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(pszDefaultAction == NULL)
{
return E_INVALIDARG;
}
if(varChild.vt==VT_I4)
{
if(varChild.lVal==CHILDID_SELF)
{
if( m_pXAction == NULL )
return DISP_E_MEMBERNOTFOUND;
SAFE_SYSFREESTRING(*pszDefaultAction);
*pszDefaultAction = SysAllocString(m_pszActionDescription);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->get_accDefaultAction(varChild,pszDefaultAction);
}
return S_FALSE;
LEAVE_PROTECTED_BLOCK
}
/**
* AT call this method to operate application
* @param varChild, the child id of the action object.
* @return S_OK if successful.
*/
HRESULT STDMETHODCALLTYPE CMAccessible::accDoDefaultAction(VARIANT varChild)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if( varChild.vt != VT_I4 )
return E_INVALIDARG;
if( m_pXAction == NULL )
return E_FAIL;
if( m_pXAction->getAccessibleActionCount() == 0 )
return E_FAIL;
if(varChild.lVal==CHILDID_SELF)
{
if(m_pXAction->getAccessibleActionCount() > 0)
m_pXAction->doAccessibleAction(0);
return S_OK;
}
long lVal = varChild.lVal;
varChild.lVal = CHILDID_SELF;
IMAccessible *pChild = this->GetChildInterface(lVal);
if(!pChild)
return E_FAIL;
return pChild->accDoDefaultAction( varChild );
LEAVE_PROTECTED_BLOCK
}
/**
* UNO set description information for action to COM.
* @param szAction, the action description of the current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::Put_ActionDescription( const OLECHAR* szAction)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(szAction == NULL)
{
return E_INVALIDARG;
}
SAFE_SYSFREESTRING(m_pszActionDescription );
m_pszActionDescription = SysAllocString( szAction );
return S_OK;
LEAVE_PROTECTED_BLOCK
}
BOOL CMAccessible::GetXInterfaceFromXAccessible(XAccessible* pXAcc, XInterface** ppXI, int index)
{
Reference< XAccessibleContext > pRContext;
switch(index)
{
case XI_COMPONENT:
QUERYXINTERFACE(AccessibleComponent)
break;
case XI_TEXT:
QUERYXINTERFACE(AccessibleText)
break;
case XI_EDITABLETEXT:
QUERYXINTERFACE(AccessibleEditableText)
break;
case XI_TABLE:
QUERYXINTERFACE(AccessibleTable)
break;
case XI_SELECTION:
QUERYXINTERFACE(AccessibleSelection)
break;
case XI_EXTENDEDCOMP:
QUERYXINTERFACE(AccessibleExtendedComponent)
break;
case XI_KEYBINDING:
QUERYXINTERFACE(AccessibleKeyBinding)
break;
case XI_ACTION:
QUERYXINTERFACE(AccessibleAction)
break;
case XI_VALUE:
QUERYXINTERFACE(AccessibleValue)
break;
case XI_HYPERTEXT:
QUERYXINTERFACE(AccessibleHypertext)
break;
case XI_HYPERLINK:
QUERYXINTERFACE(AccessibleHyperlink)
break;
case XI_IMAGE:
QUERYXINTERFACE(AccessibleImage)
break;
default:
break;
}
return FALSE;
}
HRESULT WINAPI CMAccessible::SmartQI(void* pv, REFIID iid, void** ppvObject)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if( ImplIsEqualGUID(iid,IID_IAccIdentity) ||
ImplIsEqualGUID(iid,IID_IStdMarshalInfo) ||
ImplIsEqualGUID(iid,IID_IMarshal) ||
ImplIsEqualGUID(iid,IID_IExternalConnection)||
ImplIsEqualGUID(iid,IID_IOleWindow))
return E_FAIL;
_UNO_AGGMAP_ENTRY* pMap = _GetAggEntries();
while(pMap && pMap->piid)
{
if(ImplIsEqualGUID(iid, *pMap->piid))
{
XInterface* pXI = NULL;
BOOL bFound = GetXInterfaceFromXAccessible(pUNOInterface,&pXI,pMap->XIFIndex);
if(!bFound)
{
return E_FAIL;
}
XGUIDToComObjHash::iterator pIndTemp = m_containedObjects.find( iid );
if ( pIndTemp != m_containedObjects.end() )
{
return pIndTemp->second.p->QueryInterface( iid, ppvObject );
}
else
{
ActivateActContext();
HRESULT hr = pMap->pfnCreateInstance(pv, iid, ppvObject);
DeactivateActContext();
if(hr == S_OK)
{
m_containedObjects.insert(XGUIDToComObjHash::value_type(*pMap->piid,(IUnknown*)*ppvObject));
IUNOXWrapper* wrapper = NULL;
((IUnknown*)*ppvObject)->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
if(wrapper)
{
wrapper->put_XInterface((long)pUNOInterface);
wrapper->Release();
}
return S_OK;
}
}
return E_FAIL;
}
pMap++;
}
return E_FAIL;
LEAVE_PROTECTED_BLOCK
}
BOOL CMAccessible::get_IAccessibleFromXAccessible(long pXAcc, IAccessible **ppIA)
{
ENTER_PROTECTED_BLOCK
// #CHECK#
if(ppIA == NULL)
{
return E_INVALIDARG;
}
BOOL isGet = FALSE;
if(g_pAgent)
isGet = g_pAgent->GetIAccessibleFromXAccessible((XAccessible*)pXAcc,ppIA);
if(isGet)
return TRUE;
else
return FALSE;
LEAVE_PROTECTED_BLOCK
}
void CMAccessible::get_OLECHARFromAny(Any& pAny, OLECHAR* pChar)
{
// #CHECK#
if(pChar == NULL)
return;
switch(pAny.getValueTypeClass())
{
case TypeClass_CHAR:
{
sal_Int8 val;
pAny >>= val;
swprintf( pChar, L"%d", val);
break;
}
case TypeClass_BOOLEAN:
{
sal_Bool val;
pAny >>= val;
swprintf( pChar, L"%d", val);
break;
}
case TypeClass_BYTE:
{
sal_Int8 val;
pAny >>= val;
swprintf( pChar, L"%d", val);
break;
}
case TypeClass_SHORT:
{
SHORT val;
pAny >>= val;
swprintf( pChar, L"%d", val);
break;
}
case TypeClass_UNSIGNED_SHORT:
{
USHORT val;
pAny >>= val;
swprintf( pChar, L"%d", val);
break;
}
case TypeClass_LONG:
{
LONG val;
pAny >>= val;
swprintf( pChar, L"%ld", val);
break;
}
case TypeClass_UNSIGNED_LONG:
{
ULONG val;
pAny >>= val;
swprintf( pChar, L"%ld", val);
break;
}
case TypeClass_FLOAT:
{
FLOAT val;
pAny >>= val;
swprintf( pChar, L"%.3f", val);
break;
}
case TypeClass_DOUBLE:
{
DOUBLE val;
pAny >>= val;
swprintf( pChar, L"%.6lf", val);
break;
}
case TypeClass_STRING:
{
::rtl::OUString val;
pAny >>= val;
wcscpy(pChar, val.getStr());
break;
}
case TypeClass_SEQUENCE:
{
if(pAny.getValueType() == getCppuType( (Sequence< ::rtl::OUString > *)0 ) )
{
Sequence < ::rtl::OUString > val;
pAny >>= val;
::rtl::OUString pString;
int count = val.getLength();
for( int iIndex = 0;iIndex < count;iIndex++ )
{
pString += val[iIndex];
}
wcscpy(pChar, pString.getStr());
}
else if (pAny.getValueType() == getCppuType( (Sequence< ::com::sun::star::style::TabStop >* )0 ) )
{
Sequence < ::com::sun::star::style::TabStop > val;
pAny >>= val;
int count = val.getLength();
for( int iIndex = 0;iIndex < count;iIndex++ )
{
OLECHAR pAttrs[512] = {NULL};
OLECHAR pAttrsPosition[512] = {NULL};
OLECHAR pAttrsDescimalChar[512] = {NULL};
OLECHAR pAttrsFillChar[512] = {NULL};
::com::sun::star::style::TabStop sigleVal = val[iIndex];
swprintf( pAttrsPosition, L"Position=%ld,TabAlign=%ld",
sigleVal.Position, sigleVal.Alignment);
if(sigleVal.DecimalChar==';' || sigleVal.DecimalChar == ':' || sigleVal.DecimalChar == ',' ||
sigleVal.DecimalChar == '=' || sigleVal.DecimalChar == '\\')
swprintf( pAttrsDescimalChar, L"DecimalChar=\\%c",sigleVal.DecimalChar);
else
swprintf( pAttrsDescimalChar, L"DecimalChar=%c",sigleVal.DecimalChar);
if(sigleVal.FillChar==';' || sigleVal.FillChar == ':' || sigleVal.FillChar == ',' ||
sigleVal.FillChar == '=' || sigleVal.FillChar == '\\')
swprintf( pAttrsFillChar, L"FillChar=\\%c",sigleVal.FillChar);
else
swprintf( pAttrsFillChar, L"FillChar=%c",sigleVal.FillChar);
swprintf( pAttrs, L"%s,%s,%s,",pAttrsPosition,pAttrsDescimalChar,pAttrsFillChar);
wcscat(pChar,pAttrs);
}
}
break;
}
case TypeClass_ENUM:
{
if (pAny.getValueType() == getCppuType( (::com::sun::star::awt::FontSlant* )0 ) )
{
com::sun::star::awt::FontSlant val;
pAny >>= val;
swprintf( pChar, L"%d", val);
}
}
case TypeClass_STRUCT:
{
if (pAny.getValueType() == getCppuType( (::com::sun::star::style::LineSpacing* )0 ) )
{
com::sun::star::style::LineSpacing val;
pAny >>= val;
swprintf( pChar, L"Mode=%ld,Height=%ld,", val.Mode, val.Height);
}
else if (pAny.getValueType() == getCppuType( (com::sun::star::accessibility::TextSegment *)0 ) )
{
com::sun::star::accessibility::TextSegment val;
pAny >>= val;
::rtl::OUString realVal(val.SegmentText);
wcscpy(pChar, realVal.getStr());
}
break;
}
case TypeClass_VOID:
case TypeClass_HYPER:
case TypeClass_UNSIGNED_HYPER:
case TypeClass_TYPE:
case TypeClass_ANY:
case TypeClass_TYPEDEF:
case TypeClass_UNION:
case TypeClass_EXCEPTION:
case TypeClass_ARRAY:
case TypeClass_INTERFACE:
case TypeClass_SERVICE:
case TypeClass_MODULE:
case TypeClass_INTERFACE_METHOD:
case TypeClass_INTERFACE_ATTRIBUTE:
case TypeClass_UNKNOWN:
case TypeClass_PROPERTY:
case TypeClass_CONSTANT:
case TypeClass_CONSTANTS:
case TypeClass_SINGLETON:
case TypeClass_MAKE_FIXED_SIZE:
break;
default:
break;
}
}
void CMAccessible::get_OLECHAR4Numbering(const Any& pAny, short numberingLevel,const OUString& numberingPrefix,OLECHAR* pChar)
{
if(pChar == NULL)
return;
Reference< ::com::sun::star::container::XIndexReplace > pXIndex;
if((pAny>>=pXIndex) && (numberingLevel !=-1))//numbering level is -1,means invalid value
{
Any aAny = pXIndex->getByIndex(numberingLevel);
Sequence< ::com::sun::star::beans::PropertyValue > aProps;
aAny >>= aProps;
const ::com::sun::star::beans::PropertyValue* pPropArray = aProps.getConstArray();
sal_Int32 nCount = aProps.getLength();
swprintf(pChar,L"Numbering:NumberingLevel=%d,",numberingLevel);
for( sal_Int32 i=0; i<nCount; i++ )
{
::com::sun::star::beans::PropertyValue rProp = pPropArray[i];
if( (rProp.Name.compareTo(OUString::createFromAscii("BulletChar"))==0)||
(rProp.Name.compareTo(OUString::createFromAscii("GraphicURL"))==0)||
(rProp.Name.compareTo(OUString::createFromAscii("NumberingType"))==0))
{
OLECHAR propStr[512] = {NULL};
swprintf(propStr,L"%s=",rProp.Name.getStr());
OLECHAR pTemp[256] = {NULL};
CMAccessible::get_OLECHARFromAny(rProp.Value,pTemp);
if(rProp.Name.compareTo(OUString::createFromAscii("GraphicURL"))==0)
{
OLECHAR* pOccur = wcschr(pTemp,':');
if(pOccur)
*pOccur = '.';
}
wcscat(propStr,pTemp);
wcscat(pChar,propStr);
wcscat(pChar,L",");
if(rProp.Name.compareTo(OUString::createFromAscii("NumberingType"))==0)
{
if(numberingPrefix.getLength()!=0)
{
swprintf(pTemp,L"NumberingPrefix=%s,",numberingPrefix.getStr());
wcscat(pChar,pTemp);
}
}
}
}
}
//Because now have three types numbering level:
//1.real numbering list,numbering level>=0 and numbering Rule !=NULL;
//2.common paragraph, numbering level >=0, and numbering Rule == NULL;
//3.TOC paragraph, numbering level >0, and numbering Rule ==NULL;
// IAText:numberinglevel base on 0, but TOC's level base on 1,
// so NumberingLevel value will be decreased 1 in bridge code.
else if(numberingLevel >0)
{
swprintf(pChar,L"Numbering:NumberingLevel=%d,NumberingType=4,NumberingPrefix=,",numberingLevel-1);
}
else
{
swprintf(pChar,L"Numbering:");
}
}
void CMAccessible::ConvertAnyToVariant(const ::com::sun::star::uno::Any &rAnyVal, VARIANT *pvData)
{
if(rAnyVal.hasValue())
{
// Clear VARIANT variable.
VariantClear(pvData);
// Set value according to value type.
switch(rAnyVal.getValueTypeClass())
{
case TypeClass_CHAR:
pvData->vt = VT_UI1;
memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Char));
break;
case TypeClass_BOOLEAN:
pvData->vt = VT_BOOL;
memcpy(&pvData->boolVal, rAnyVal.getValue(), sizeof(sal_Bool));
break;
case TypeClass_BYTE:
pvData->vt = VT_UI1;
memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Int8));
break;
case TypeClass_SHORT:
pvData->vt = VT_I2;
memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_Int16));
break;
case TypeClass_UNSIGNED_SHORT:
pvData->vt = VT_I2;
memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_uInt16));
break;
case TypeClass_LONG:
pvData->vt = VT_I4;
memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_Int32));
break;
case TypeClass_UNSIGNED_LONG:
pvData->vt = VT_I4;
memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_uInt32));
break;
case TypeClass_FLOAT:
pvData->vt = VT_R4;
memcpy(&pvData->fltVal, rAnyVal.getValue(), sizeof(float));
break;
case TypeClass_DOUBLE:
pvData->vt = VT_R8;
memcpy(&pvData->dblVal, rAnyVal.getValue(), sizeof(double));
break;
case TypeClass_STRING:
{
pvData->vt = VT_BSTR;
::rtl::OUString val;
rAnyVal >>= val;
pvData->bstrVal = SysAllocString((OLECHAR *)val.getStr());
break;
}
case TypeClass_VOID:
case TypeClass_HYPER:
case TypeClass_UNSIGNED_HYPER:
case TypeClass_TYPE:
case TypeClass_ANY:
case TypeClass_ENUM:
case TypeClass_TYPEDEF:
case TypeClass_STRUCT:
case TypeClass_UNION:
case TypeClass_EXCEPTION:
case TypeClass_SEQUENCE:
case TypeClass_ARRAY:
case TypeClass_INTERFACE:
{
Reference< XAccessible > pXAcc;
if(rAnyVal >>= pXAcc)
{
if(pXAcc.is())
{
IAccessible* pIAcc = NULL;
get_IAccessibleFromXAccessible((long)pXAcc.get(), &pIAcc);
if(pIAcc == NULL)
{
Reference< XAccessibleContext > pXAccContext = pXAcc->getAccessibleContext();
g_pAgent->InsertAccObj(pXAcc.get(),pXAccContext->getAccessibleParent().get());
get_IAccessibleFromXAccessible((long)pXAcc.get(), &pIAcc);
}
if(pIAcc)
{
pIAcc->AddRef();
pvData->vt = VT_UNKNOWN;
pvData->pdispVal = (IAccessible2*)pIAcc;
break;
}
}
}
}
case TypeClass_SERVICE:
case TypeClass_MODULE:
case TypeClass_INTERFACE_METHOD:
case TypeClass_INTERFACE_ATTRIBUTE:
case TypeClass_UNKNOWN:
case TypeClass_PROPERTY:
case TypeClass_CONSTANT:
case TypeClass_CONSTANTS:
case TypeClass_SINGLETON:
case TypeClass_MAKE_FIXED_SIZE:
// Output the type string, if there is other uno value type.
pvData->vt = VT_BSTR;
pvData->bstrVal = SysAllocString(rAnyVal.getValueTypeName().getStr());
break;
default:
break;
}
}
else
{
VariantClear(pvData);
}
}
STDMETHODIMP CMAccessible::Get_XAccChildID(long* childID)
{
// #CHECK#
if(childID == NULL)
{
return E_FAIL;
}
*childID = m_dChildID;
return S_OK;
}
STDMETHODIMP CMAccessible:: get_states(AccessibleStates __RPC_FAR *states )
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK XInterface#
if( !pRContext.is() )
return E_FAIL;
Reference<XAccessibleStateSet> pRStateSet = pRContext.get()->getAccessibleStateSet();
if(!pRStateSet.is())
{
return S_OK;
}
Sequence<short> pStates = pRStateSet->getStates();
long count = pStates.getLength() ;
*states = 0x0;
for( int i = 0; i < count; i++ )
{
for( int j = 0; j < sizeof(UNO_STATES) / sizeof(UNO_STATES[0]); j++ )
{
if( pStates[i] == UNO_STATES[j] )
{
*states |= IA2_STATES[j];
break;
}
}
}
return S_OK;
LEAVE_PROTECTED_BLOCK
}
// return the UNO roles
STDMETHODIMP CMAccessible:: get_extendedRole( BSTR __RPC_FAR * )
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_localizedExtendedRole( BSTR __RPC_FAR * )
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_nExtendedStates( long __RPC_FAR * )
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_localizedExtendedStates( long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
return E_NOTIMPL;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_indexInParent( long __RPC_FAR *accParentIndex)
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
// #CHECK#
if(accParentIndex == NULL)
return E_INVALIDARG;
// #CHECK XInterface#
if( !pRContext.is() )
return E_FAIL;
*accParentIndex = pRContext.get()->getAccessibleIndexInParent();
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_locale( IA2Locale __RPC_FAR *locale )
{
CHECK_ENABLE_INF
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(locale == NULL)
return E_INVALIDARG;
// #CHECK XInterface#
if( !pRContext.is() )
return E_FAIL;
::com::sun::star::lang::Locale unoLoc = pRContext.get()->getLocale();
locale->language = SysAllocString((OLECHAR*)unoLoc.Language.getStr());
locale->country = SysAllocString((OLECHAR*)unoLoc.Country.getStr());
locale->variant = SysAllocString((OLECHAR*)unoLoc.Variant.getStr());
return S_OK;
LEAVE_PROTECTED_BLOCK
}
DWORD GetMSAAStateFromUNO(short xState)
{
DWORD IState = STATE_SYSTEM_UNAVAILABLE;
switch( xState )
{
case /*AccessibleStateType::*/AccessibleStateType::BUSY:
IState = STATE_SYSTEM_BUSY;
break;
case /*AccessibleStateType::*/AccessibleStateType::CHECKED:
IState = STATE_SYSTEM_CHECKED;
break;
case /*AccessibleStateType::*/AccessibleStateType::DEFUNC:
IState = STATE_SYSTEM_UNAVAILABLE;
break;
case /*AccessibleStateType::*/AccessibleStateType::EXPANDED:
IState = STATE_SYSTEM_EXPANDED;
break;
case /*AccessibleStateType::*/AccessibleStateType::FOCUSABLE:
IState = STATE_SYSTEM_FOCUSABLE;
break;
case /*AccessibleStateType::*/AccessibleStateType::FOCUSED:
IState = STATE_SYSTEM_FOCUSED;
break;
case /*AccessibleStateType::*/AccessibleStateType::INDETERMINATE:
IState = STATE_SYSTEM_MIXED;
break;
case /*AccessibleStateType::*/AccessibleStateType::MULTI_SELECTABLE:
IState = STATE_SYSTEM_MULTISELECTABLE;
break;
case /*AccessibleStateType::*/AccessibleStateType::PRESSED:
IState = STATE_SYSTEM_PRESSED;
break;
case /*AccessibleStateType::*/AccessibleStateType::RESIZABLE:
IState = STATE_SYSTEM_SIZEABLE;
break;
case /*AccessibleStateType::*/AccessibleStateType::SELECTABLE:
IState = STATE_SYSTEM_SELECTABLE;
break;
case /*AccessibleStateType::*/AccessibleStateType::SELECTED:
IState = STATE_SYSTEM_SELECTED;
break;
case /*AccessibleStateType::*/AccessibleStateType::ARMED:
IState = STATE_SYSTEM_FOCUSED;
break;
case /*AccessibleStateType::*/AccessibleStateType::EXPANDABLE:
IState = STATE_SYSTEM_COLLAPSED;
break;
default:
break;
}
return IState;
}
STDMETHODIMP CMAccessible:: get_appName( BSTR __RPC_FAR *name)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(name == NULL)
return E_INVALIDARG;
*name = SysAllocString(OLESTR("Hannover"));
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_appVersion(BSTR __RPC_FAR *version)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(version == NULL)
return E_INVALIDARG;
*version=SysAllocString(OLESTR("3.0"));
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_toolkitName(BSTR __RPC_FAR *name)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(name == NULL)
return E_INVALIDARG;
*name = SysAllocString(OLESTR(" "));
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_toolkitVersion(BSTR __RPC_FAR *version)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
if(version == NULL)
return E_INVALIDARG;
*version = SysAllocString(OLESTR(" "));
return S_OK;
LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible::get_attributes(/*[out]*/ BSTR *pAttr)
{
ENTER_PROTECTED_BLOCK
ISDESTROY()
CHECK_ENABLE_INF
Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
if( !pRContext.is() )
{
return E_FAIL;
}
Reference<XAccessibleExtendedAttributes> pRXI(pRContext,UNO_QUERY);
if( !pRXI.is() )
return E_FAIL;
else
{
com::sun::star::uno::Reference<com::sun::star::accessibility::XAccessibleExtendedAttributes> pRXAttr;
pRXAttr = pRXI.get();
::com::sun::star::uno::Any anyVal = pRXAttr->getExtendedAttributes();
::rtl::OUString val;
anyVal >>= val;
if(*pAttr)
SAFE_SYSFREESTRING(*pAttr);
*pAttr = SysAllocString((OLECHAR *)val.getStr());
return S_OK;
}
LEAVE_PROTECTED_BLOCK
}