forked from amazingfate/loongoffice
The change allowed to simplify many places where previously this API was used, to avoid inefficient calculations (e.g., moving rectangle keeping its size, and then immediately changing the size). Change-Id: Ica2dc594d91cae83e2c2740c1f4fb23f44998916 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120461 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
866 lines
26 KiB
C++
866 lines
26 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* 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 .
|
|
*/
|
|
|
|
#include <AccessibleBase.hxx>
|
|
#include "AccessibleChartShape.hxx"
|
|
#include <ObjectHierarchy.hxx>
|
|
#include <ObjectIdentifier.hxx>
|
|
#include <chartview/ExplicitValueProvider.hxx>
|
|
|
|
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleEventObject.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleRole.hpp>
|
|
#include <com/sun/star/drawing/LineStyle.hpp>
|
|
#include <com/sun/star/drawing/FillStyle.hpp>
|
|
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
|
|
#include <com/sun/star/view/XSelectionSupplier.hpp>
|
|
#include <com/sun/star/chart2/XChartDocument.hpp>
|
|
#include <sal/log.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <comphelper/servicehelper.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <i18nlangtag/languagetag.hxx>
|
|
#include <vcl/unohelp.hxx>
|
|
#include <toolkit/helper/vclunohelper.hxx>
|
|
#include <vcl/window.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <o3tl/functional.hxx>
|
|
#include <o3tl/safeint.hxx>
|
|
#include <tools/diagnose_ex.h>
|
|
#include <unotools/accessiblestatesethelper.hxx>
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
#include "ChartElementFactory.hxx"
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::accessibility;
|
|
|
|
using ::com::sun::star::uno::UNO_QUERY;
|
|
using ::com::sun::star::uno::Reference;
|
|
using ::osl::MutexGuard;
|
|
using ::osl::ClearableMutexGuard;
|
|
using ::com::sun::star::uno::Any;
|
|
|
|
namespace chart
|
|
{
|
|
|
|
/** @param bMayHaveChildren is false per default
|
|
*/
|
|
AccessibleBase::AccessibleBase(
|
|
const AccessibleElementInfo & rAccInfo,
|
|
bool bMayHaveChildren,
|
|
bool bAlwaysTransparent /* default: false */ ) :
|
|
impl::AccessibleBase_Base( m_aMutex ),
|
|
m_bIsDisposed( false ),
|
|
m_bMayHaveChildren( bMayHaveChildren ),
|
|
m_bChildrenInitialized( false ),
|
|
m_nEventNotifierId(0),
|
|
m_xStateSetHelper( new ::utl::AccessibleStateSetHelper() ),
|
|
m_aAccInfo( rAccInfo ),
|
|
m_bAlwaysTransparent( bAlwaysTransparent ),
|
|
m_bStateSetInitialized( false )
|
|
{
|
|
// initialize some states
|
|
OSL_ASSERT( m_xStateSetHelper.is() );
|
|
m_xStateSetHelper->AddState( AccessibleStateType::ENABLED );
|
|
m_xStateSetHelper->AddState( AccessibleStateType::SHOWING );
|
|
m_xStateSetHelper->AddState( AccessibleStateType::VISIBLE );
|
|
m_xStateSetHelper->AddState( AccessibleStateType::SELECTABLE );
|
|
m_xStateSetHelper->AddState( AccessibleStateType::FOCUSABLE );
|
|
}
|
|
|
|
AccessibleBase::~AccessibleBase()
|
|
{
|
|
OSL_ASSERT( m_bIsDisposed );
|
|
}
|
|
|
|
bool AccessibleBase::CheckDisposeState( bool bThrowException /* default: true */ ) const
|
|
{
|
|
if( bThrowException &&
|
|
m_bIsDisposed )
|
|
{
|
|
throw lang::DisposedException("component has state DEFUNC",
|
|
static_cast< uno::XWeak * >( const_cast< AccessibleBase * >( this )));
|
|
}
|
|
return m_bIsDisposed;
|
|
}
|
|
|
|
bool AccessibleBase::NotifyEvent( EventType eEventType, const AccessibleUniqueId & rId )
|
|
{
|
|
if( GetId() == rId )
|
|
{
|
|
// event is addressed to this object
|
|
|
|
css::uno::Any aEmpty;
|
|
css::uno::Any aSelected;
|
|
aSelected <<= AccessibleStateType::SELECTED;
|
|
switch( eEventType )
|
|
{
|
|
case EventType::GOT_SELECTION:
|
|
{
|
|
AddState( AccessibleStateType::SELECTED );
|
|
BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty );
|
|
|
|
AddState( AccessibleStateType::FOCUSED );
|
|
aSelected <<= AccessibleStateType::FOCUSED;
|
|
BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty, true );
|
|
|
|
SAL_INFO("chart2.accessibility", "Selection acquired by: " << getAccessibleName());
|
|
}
|
|
break;
|
|
|
|
case EventType::LOST_SELECTION:
|
|
{
|
|
RemoveState( AccessibleStateType::SELECTED );
|
|
BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected );
|
|
|
|
AddState( AccessibleStateType::FOCUSED );
|
|
aSelected <<= AccessibleStateType::FOCUSED;
|
|
BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected, true );
|
|
SAL_INFO("chart2.accessibility", "Selection lost by: " << getAccessibleName());
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
else if( m_bMayHaveChildren )
|
|
{
|
|
bool bStop = false;
|
|
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
// make local copy for notification
|
|
ChildListVectorType aLocalChildList( m_aChildList );
|
|
aGuard.clear();
|
|
|
|
for (auto const& localChild : aLocalChildList)
|
|
{
|
|
// Note: at this place we must be sure to have an AccessibleBase
|
|
// object in the UNO reference to XAccessible !
|
|
bStop = (*static_cast< AccessibleBase * >
|
|
( localChild.get() )).NotifyEvent( eEventType, rId );
|
|
if (bStop)
|
|
break;
|
|
}
|
|
return bStop;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void AccessibleBase::AddState( sal_Int16 aState )
|
|
{
|
|
CheckDisposeState();
|
|
OSL_ASSERT( m_xStateSetHelper.is() );
|
|
m_xStateSetHelper->AddState( aState );
|
|
}
|
|
|
|
void AccessibleBase::RemoveState( sal_Int16 aState )
|
|
{
|
|
CheckDisposeState();
|
|
OSL_ASSERT( m_xStateSetHelper.is() );
|
|
m_xStateSetHelper->RemoveState( aState );
|
|
}
|
|
|
|
bool AccessibleBase::UpdateChildren()
|
|
{
|
|
bool bMustUpdateChildren = false;
|
|
{
|
|
MutexGuard aGuard( m_aMutex );
|
|
if( ! m_bMayHaveChildren ||
|
|
m_bIsDisposed )
|
|
return false;
|
|
|
|
bMustUpdateChildren = ( m_bMayHaveChildren &&
|
|
! m_bChildrenInitialized );
|
|
}
|
|
|
|
// update unguarded
|
|
if( bMustUpdateChildren )
|
|
m_bChildrenInitialized = ImplUpdateChildren();
|
|
|
|
return m_bChildrenInitialized;
|
|
}
|
|
|
|
bool AccessibleBase::ImplUpdateChildren()
|
|
{
|
|
bool bResult = false;
|
|
|
|
if( m_aAccInfo.m_spObjectHierarchy )
|
|
{
|
|
ObjectHierarchy::tChildContainer aModelChildren(
|
|
m_aAccInfo.m_spObjectHierarchy->getChildren( GetId() ));
|
|
std::vector< ChildOIDMap::key_type > aAccChildren;
|
|
aAccChildren.reserve( aModelChildren.size());
|
|
std::transform( m_aChildOIDMap.begin(), m_aChildOIDMap.end(),
|
|
std::back_inserter( aAccChildren ),
|
|
::o3tl::select1st< ChildOIDMap::value_type >() );
|
|
|
|
std::sort( aModelChildren.begin(), aModelChildren.end());
|
|
|
|
std::vector< ObjectIdentifier > aChildrenToRemove, aChildrenToAdd;
|
|
std::set_difference( aModelChildren.begin(), aModelChildren.end(),
|
|
aAccChildren.begin(), aAccChildren.end(),
|
|
std::back_inserter( aChildrenToAdd ));
|
|
std::set_difference( aAccChildren.begin(), aAccChildren.end(),
|
|
aModelChildren.begin(), aModelChildren.end(),
|
|
std::back_inserter( aChildrenToRemove ));
|
|
|
|
for (auto const& childToRemove : aChildrenToRemove)
|
|
{
|
|
RemoveChildByOId(childToRemove);
|
|
}
|
|
|
|
AccessibleElementInfo aAccInfo( GetInfo());
|
|
aAccInfo.m_pParent = this;
|
|
|
|
for (auto const& childToAdd : aChildrenToAdd)
|
|
{
|
|
aAccInfo.m_aOID = childToAdd;
|
|
if ( childToAdd.isAutoGeneratedObject() )
|
|
{
|
|
AddChild( ChartElementFactory::CreateChartElement( aAccInfo ).get() );
|
|
}
|
|
else if ( childToAdd.isAdditionalShape() )
|
|
{
|
|
AddChild( new AccessibleChartShape( aAccInfo ) );
|
|
}
|
|
}
|
|
bResult = true;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void AccessibleBase::AddChild( AccessibleBase * pChild )
|
|
{
|
|
OSL_ENSURE( pChild != nullptr, "Invalid Child" );
|
|
if( !pChild )
|
|
return;
|
|
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
|
|
Reference< XAccessible > xChild( pChild );
|
|
m_aChildList.push_back( xChild );
|
|
|
|
m_aChildOIDMap[ pChild->GetId() ] = xChild;
|
|
|
|
// inform listeners of new child
|
|
if( m_bChildrenInitialized )
|
|
{
|
|
Any aEmpty, aNew;
|
|
aNew <<= xChild;
|
|
|
|
aGuard.clear();
|
|
BroadcastAccEvent( AccessibleEventId::CHILD, aNew, aEmpty );
|
|
}
|
|
}
|
|
|
|
/** in this method we imply that the Reference< XAccessible > elements in the
|
|
vector are AccessibleBase objects !
|
|
*/
|
|
void AccessibleBase::RemoveChildByOId( const ObjectIdentifier& rOId )
|
|
{
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
|
|
ChildOIDMap::iterator aIt( m_aChildOIDMap.find( rOId ));
|
|
if( aIt == m_aChildOIDMap.end())
|
|
return;
|
|
|
|
Reference< XAccessible > xChild( aIt->second );
|
|
|
|
// remove from map
|
|
m_aChildOIDMap.erase( aIt );
|
|
|
|
// search child in vector
|
|
ChildListVectorType::iterator aVecIter =
|
|
std::find( m_aChildList.begin(), m_aChildList.end(), xChild );
|
|
|
|
OSL_ENSURE( aVecIter != m_aChildList.end(),
|
|
"Inconsistent ChildMap" );
|
|
|
|
// remove child from vector
|
|
m_aChildList.erase( aVecIter );
|
|
bool bInitialized = m_bChildrenInitialized;
|
|
|
|
// call listeners unguarded
|
|
aGuard.clear();
|
|
|
|
// inform listeners of removed child
|
|
if( bInitialized )
|
|
{
|
|
Any aEmpty, aOld;
|
|
aOld <<= xChild;
|
|
|
|
BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld );
|
|
}
|
|
|
|
// dispose the child
|
|
Reference< lang::XComponent > xComp( xChild, UNO_QUERY );
|
|
if( xComp.is())
|
|
xComp->dispose();
|
|
}
|
|
|
|
awt::Point AccessibleBase::GetUpperLeftOnScreen() const
|
|
{
|
|
awt::Point aResult;
|
|
if( m_aAccInfo.m_pParent )
|
|
{
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
AccessibleBase * pParent = m_aAccInfo.m_pParent;
|
|
aGuard.clear();
|
|
|
|
if( pParent )
|
|
{
|
|
aResult = pParent->GetUpperLeftOnScreen();
|
|
}
|
|
else
|
|
OSL_FAIL( "Default position used is probably incorrect." );
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
void AccessibleBase::BroadcastAccEvent(
|
|
sal_Int16 nId,
|
|
const Any & rNew,
|
|
const Any & rOld,
|
|
bool bSendGlobally ) const
|
|
{
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
|
|
if ( !m_nEventNotifierId && !bSendGlobally )
|
|
return;
|
|
// if we don't have a client id for the notifier, then we don't have listeners, then
|
|
// we don't need to notify anything
|
|
//except SendGlobally for focus handling?
|
|
|
|
// the const cast is needed, because UNO parameters are never const
|
|
const AccessibleEventObject aEvent(
|
|
const_cast< uno::XWeak * >( static_cast< const uno::XWeak * >( this )),
|
|
nId, rNew, rOld );
|
|
|
|
if ( m_nEventNotifierId ) // let the notifier handle this event
|
|
::comphelper::AccessibleEventNotifier::addEvent( m_nEventNotifierId, aEvent );
|
|
|
|
aGuard.clear();
|
|
|
|
// send event to global message queue
|
|
if( bSendGlobally )
|
|
{
|
|
vcl::unohelper::NotifyAccessibleStateEventGlobally( aEvent );
|
|
}
|
|
}
|
|
|
|
void AccessibleBase::KillAllChildren()
|
|
{
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
|
|
// make local copy for notification, and remove all children
|
|
ChildListVectorType aLocalChildList;
|
|
aLocalChildList.swap( m_aChildList );
|
|
m_aChildOIDMap.clear();
|
|
|
|
aGuard.clear();
|
|
|
|
// call dispose for all children
|
|
// and notify listeners
|
|
Reference< lang::XComponent > xComp;
|
|
Any aEmpty, aOld;
|
|
for (auto const& localChild : aLocalChildList)
|
|
{
|
|
aOld <<= localChild;
|
|
BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld );
|
|
|
|
xComp.set(localChild, UNO_QUERY);
|
|
if( xComp.is())
|
|
xComp->dispose();
|
|
}
|
|
m_bChildrenInitialized = false;
|
|
}
|
|
|
|
void AccessibleBase::SetInfo( const AccessibleElementInfo & rNewInfo )
|
|
{
|
|
m_aAccInfo = rNewInfo;
|
|
if( m_bMayHaveChildren )
|
|
{
|
|
KillAllChildren();
|
|
}
|
|
BroadcastAccEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, uno::Any(), uno::Any(),
|
|
true /* global notification */ );
|
|
}
|
|
|
|
// ________ (XComponent::dispose) ________
|
|
void SAL_CALL AccessibleBase::disposing()
|
|
{
|
|
{
|
|
MutexGuard aGuard(m_aMutex);
|
|
OSL_ENSURE(!m_bIsDisposed, "dispose() called twice");
|
|
|
|
// notify disposing to all AccessibleEvent listeners asynchronous
|
|
if (m_nEventNotifierId)
|
|
{
|
|
::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(m_nEventNotifierId,
|
|
*this);
|
|
m_nEventNotifierId = 0;
|
|
}
|
|
|
|
// reset pointers
|
|
m_aAccInfo.m_pParent = nullptr;
|
|
|
|
// attach new empty state set helper to member reference
|
|
rtl::Reference<::utl::AccessibleStateSetHelper> pHelper = new ::utl::AccessibleStateSetHelper();
|
|
pHelper->AddState(AccessibleStateType::DEFUNC);
|
|
// release old helper and attach new one
|
|
m_xStateSetHelper = pHelper;
|
|
|
|
m_bIsDisposed = true;
|
|
|
|
}
|
|
// call listeners unguarded
|
|
|
|
if( m_bMayHaveChildren )
|
|
{
|
|
KillAllChildren();
|
|
}
|
|
else
|
|
OSL_ENSURE( m_aChildList.empty(), "Child list should be empty" );
|
|
}
|
|
|
|
// ________ XAccessible ________
|
|
Reference< XAccessibleContext > SAL_CALL AccessibleBase::getAccessibleContext()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
// ________ AccessibleBase::XAccessibleContext ________
|
|
sal_Int32 SAL_CALL AccessibleBase::getAccessibleChildCount()
|
|
{
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
if( ! m_bMayHaveChildren ||
|
|
m_bIsDisposed )
|
|
return 0;
|
|
|
|
bool bMustUpdateChildren = ( m_bMayHaveChildren &&
|
|
! m_bChildrenInitialized );
|
|
|
|
aGuard.clear();
|
|
|
|
// update unguarded
|
|
if( bMustUpdateChildren )
|
|
UpdateChildren();
|
|
|
|
return ImplGetAccessibleChildCount();
|
|
}
|
|
|
|
sal_Int32 AccessibleBase::ImplGetAccessibleChildCount() const
|
|
{
|
|
return m_aChildList.size();
|
|
}
|
|
|
|
Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleChild( sal_Int32 i )
|
|
{
|
|
CheckDisposeState();
|
|
Reference< XAccessible > xResult;
|
|
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
bool bMustUpdateChildren = ( m_bMayHaveChildren &&
|
|
! m_bChildrenInitialized );
|
|
|
|
aGuard.clear();
|
|
|
|
if( bMustUpdateChildren )
|
|
UpdateChildren();
|
|
|
|
xResult.set( ImplGetAccessibleChildById( i ));
|
|
|
|
return xResult;
|
|
}
|
|
|
|
Reference< XAccessible > AccessibleBase::ImplGetAccessibleChildById( sal_Int32 i ) const
|
|
{
|
|
Reference< XAccessible > xResult;
|
|
|
|
MutexGuard aGuard( m_aMutex);
|
|
if( ! m_bMayHaveChildren ||
|
|
i < 0 ||
|
|
o3tl::make_unsigned( i ) >= m_aChildList.size() )
|
|
{
|
|
OUString aBuf = "Index " + OUString::number( i ) + " is invalid for range [ 0, " +
|
|
OUString::number( m_aChildList.size() - 1 ) +
|
|
" ]";
|
|
lang::IndexOutOfBoundsException aEx( aBuf,
|
|
const_cast< ::cppu::OWeakObject * >(
|
|
static_cast< const ::cppu::OWeakObject * >( this )));
|
|
throw aEx;
|
|
}
|
|
else
|
|
xResult.set( m_aChildList[ i ] );
|
|
|
|
return xResult;
|
|
}
|
|
|
|
Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleParent()
|
|
{
|
|
CheckDisposeState();
|
|
Reference< XAccessible > aResult;
|
|
if( m_aAccInfo.m_pParent )
|
|
aResult.set( m_aAccInfo.m_pParent );
|
|
|
|
return aResult;
|
|
}
|
|
|
|
sal_Int32 SAL_CALL AccessibleBase::getAccessibleIndexInParent()
|
|
{
|
|
CheckDisposeState();
|
|
|
|
if( m_aAccInfo.m_spObjectHierarchy )
|
|
return m_aAccInfo.m_spObjectHierarchy->getIndexInParent( GetId() );
|
|
return -1;
|
|
}
|
|
|
|
sal_Int16 SAL_CALL AccessibleBase::getAccessibleRole()
|
|
{
|
|
return AccessibleRole::SHAPE;
|
|
}
|
|
|
|
Reference< XAccessibleRelationSet > SAL_CALL AccessibleBase::getAccessibleRelationSet()
|
|
{
|
|
Reference< XAccessibleRelationSet > aResult;
|
|
return aResult;
|
|
}
|
|
|
|
Reference< XAccessibleStateSet > SAL_CALL AccessibleBase::getAccessibleStateSet()
|
|
{
|
|
if( ! m_bStateSetInitialized )
|
|
{
|
|
Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier );
|
|
if ( xSelSupp.is() )
|
|
{
|
|
ObjectIdentifier aOID( xSelSupp->getSelection() );
|
|
if ( aOID.isValid() && GetId() == aOID )
|
|
{
|
|
AddState( AccessibleStateType::SELECTED );
|
|
AddState( AccessibleStateType::FOCUSED );
|
|
}
|
|
}
|
|
m_bStateSetInitialized = true;
|
|
}
|
|
|
|
return m_xStateSetHelper;
|
|
}
|
|
|
|
lang::Locale SAL_CALL AccessibleBase::getLocale()
|
|
{
|
|
CheckDisposeState();
|
|
|
|
return Application::GetSettings().GetLanguageTag().getLocale();
|
|
}
|
|
|
|
// ________ AccessibleBase::XAccessibleComponent ________
|
|
sal_Bool SAL_CALL AccessibleBase::containsPoint( const awt::Point& aPoint )
|
|
{
|
|
awt::Rectangle aRect( getBounds() );
|
|
|
|
// contains() works with relative coordinates
|
|
aRect.X = 0;
|
|
aRect.Y = 0;
|
|
|
|
return ( aPoint.X >= aRect.X &&
|
|
aPoint.Y >= aRect.Y &&
|
|
aPoint.X < (aRect.X + aRect.Width) &&
|
|
aPoint.Y < (aRect.Y + aRect.Height) );
|
|
}
|
|
|
|
Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleAtPoint( const awt::Point& aPoint )
|
|
{
|
|
CheckDisposeState();
|
|
Reference< XAccessible > aResult;
|
|
awt::Rectangle aRect( getBounds());
|
|
|
|
// children are positioned relative to this object, so translate bound rect
|
|
aRect.X = 0;
|
|
aRect.Y = 0;
|
|
|
|
// children must be inside the own bound rect
|
|
if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) &&
|
|
( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height)))
|
|
{
|
|
ClearableMutexGuard aGuard( m_aMutex );
|
|
ChildListVectorType aLocalChildList( m_aChildList );
|
|
aGuard.clear();
|
|
|
|
Reference< XAccessibleComponent > aComp;
|
|
for (auto const& localChild : aLocalChildList)
|
|
{
|
|
aComp.set(localChild, UNO_QUERY);
|
|
if( aComp.is())
|
|
{
|
|
aRect = aComp->getBounds();
|
|
if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) &&
|
|
( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height)))
|
|
{
|
|
aResult = localChild;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
awt::Rectangle SAL_CALL AccessibleBase::getBounds()
|
|
{
|
|
ExplicitValueProvider *pExplicitValueProvider(
|
|
comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_aAccInfo.m_xView ));
|
|
if( pExplicitValueProvider )
|
|
{
|
|
VclPtr<vcl::Window> pWindow( VCLUnoHelper::GetWindow( m_aAccInfo.m_xWindow ));
|
|
awt::Rectangle aLogicRect( pExplicitValueProvider->getRectangleOfObject( m_aAccInfo.m_aOID.getObjectCID() ));
|
|
if( pWindow )
|
|
{
|
|
tools::Rectangle aRect( aLogicRect.X, aLogicRect.Y,
|
|
aLogicRect.X + aLogicRect.Width,
|
|
aLogicRect.Y + aLogicRect.Height );
|
|
SolarMutexGuard aSolarGuard;
|
|
aRect = pWindow->LogicToPixel( aRect );
|
|
|
|
// aLogicRect is relative to the page, but we need a value relative
|
|
// to the parent object
|
|
awt::Point aParentLocOnScreen;
|
|
uno::Reference< XAccessibleComponent > xParent( getAccessibleParent(), uno::UNO_QUERY );
|
|
if( xParent.is() )
|
|
aParentLocOnScreen = xParent->getLocationOnScreen();
|
|
|
|
awt::Point aULOnScreen = GetUpperLeftOnScreen();
|
|
awt::Point aOffset( aParentLocOnScreen.X - aULOnScreen.X,
|
|
aParentLocOnScreen.Y - aULOnScreen.Y );
|
|
|
|
return awt::Rectangle( aRect.Left() - aOffset.X, aRect.Top() - aOffset.Y,
|
|
aRect.getWidth(), aRect.getHeight());
|
|
}
|
|
}
|
|
|
|
return awt::Rectangle();
|
|
}
|
|
|
|
awt::Point SAL_CALL AccessibleBase::getLocation()
|
|
{
|
|
CheckDisposeState();
|
|
awt::Rectangle aBBox( getBounds() );
|
|
return awt::Point( aBBox.X, aBBox.Y );
|
|
}
|
|
|
|
awt::Point SAL_CALL AccessibleBase::getLocationOnScreen()
|
|
{
|
|
CheckDisposeState();
|
|
|
|
if (AccessibleBase* pParent = m_aAccInfo.m_pParent)
|
|
{
|
|
awt::Point aLocThisRel( getLocation());
|
|
awt::Point aUpperLeft(pParent->getLocationOnScreen());
|
|
|
|
return awt::Point( aUpperLeft.X + aLocThisRel.X,
|
|
aUpperLeft.Y + aLocThisRel.Y );
|
|
}
|
|
else
|
|
return getLocation();
|
|
}
|
|
|
|
awt::Size SAL_CALL AccessibleBase::getSize()
|
|
{
|
|
CheckDisposeState();
|
|
awt::Rectangle aBBox( getBounds() );
|
|
return awt::Size( aBBox.Width, aBBox.Height );
|
|
}
|
|
|
|
void SAL_CALL AccessibleBase::grabFocus()
|
|
{
|
|
CheckDisposeState();
|
|
|
|
Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier );
|
|
if ( xSelSupp.is() )
|
|
{
|
|
xSelSupp->select( GetId().getAny() );
|
|
}
|
|
}
|
|
|
|
sal_Int32 SAL_CALL AccessibleBase::getForeground()
|
|
{
|
|
return sal_Int32(getColor( ACC_BASE_FOREGROUND ));
|
|
}
|
|
|
|
sal_Int32 SAL_CALL AccessibleBase::getBackground()
|
|
{
|
|
return sal_Int32(getColor( ACC_BASE_BACKGROUND ));
|
|
}
|
|
|
|
Color AccessibleBase::getColor( eColorType eColType )
|
|
{
|
|
Color nResult = COL_TRANSPARENT;
|
|
if( m_bAlwaysTransparent )
|
|
return nResult;
|
|
|
|
ObjectIdentifier aOID( m_aAccInfo.m_aOID );
|
|
ObjectType eType( aOID.getObjectType() );
|
|
Reference< beans::XPropertySet > xObjProp;
|
|
OUString aObjectCID = aOID.getObjectCID();
|
|
if( eType == OBJECTTYPE_LEGEND_ENTRY )
|
|
{
|
|
// for colors get the data series/point properties
|
|
OUString aParentParticle( ObjectIdentifier::getFullParentParticle( aObjectCID ));
|
|
aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle );
|
|
}
|
|
|
|
xObjProp =
|
|
ObjectIdentifier::getObjectPropertySet(
|
|
aObjectCID, Reference< chart2::XChartDocument >( m_aAccInfo.m_xChartDocument ));
|
|
if( xObjProp.is())
|
|
{
|
|
try
|
|
{
|
|
OUString aPropName;
|
|
OUString aStylePropName;
|
|
|
|
switch( eType )
|
|
{
|
|
case OBJECTTYPE_LEGEND_ENTRY:
|
|
case OBJECTTYPE_DATA_SERIES:
|
|
case OBJECTTYPE_DATA_POINT:
|
|
if( eColType == ACC_BASE_FOREGROUND )
|
|
{
|
|
aPropName = "BorderColor";
|
|
aStylePropName = "BorderTransparency";
|
|
}
|
|
else
|
|
{
|
|
aPropName = "Color";
|
|
aStylePropName = "Transparency";
|
|
}
|
|
break;
|
|
default:
|
|
if( eColType == ACC_BASE_FOREGROUND )
|
|
{
|
|
aPropName = "LineColor";
|
|
aStylePropName = "LineTransparence";
|
|
}
|
|
else
|
|
{
|
|
aPropName = "FillColor";
|
|
aStylePropName = "FillTransparence";
|
|
}
|
|
break;
|
|
}
|
|
|
|
bool bTransparent = m_bAlwaysTransparent;
|
|
Reference< beans::XPropertySetInfo > xInfo = xObjProp->getPropertySetInfo();
|
|
if( xInfo.is() &&
|
|
xInfo->hasPropertyByName( aStylePropName ))
|
|
{
|
|
if( eColType == ACC_BASE_FOREGROUND )
|
|
{
|
|
drawing::LineStyle aLStyle;
|
|
if( xObjProp->getPropertyValue( aStylePropName ) >>= aLStyle )
|
|
bTransparent = (aLStyle == drawing::LineStyle_NONE);
|
|
}
|
|
else
|
|
{
|
|
drawing::FillStyle aFStyle;
|
|
if( xObjProp->getPropertyValue( aStylePropName ) >>= aFStyle )
|
|
bTransparent = (aFStyle == drawing::FillStyle_NONE);
|
|
}
|
|
}
|
|
|
|
if( !bTransparent &&
|
|
xInfo.is() &&
|
|
xInfo->hasPropertyByName( aPropName ))
|
|
{
|
|
xObjProp->getPropertyValue( aPropName ) >>= nResult;
|
|
}
|
|
}
|
|
catch( const uno::Exception & )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("chart2");
|
|
}
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
// ________ AccessibleBase::XServiceInfo ________
|
|
OUString SAL_CALL AccessibleBase::getImplementationName()
|
|
{
|
|
return "AccessibleBase";
|
|
}
|
|
|
|
sal_Bool SAL_CALL AccessibleBase::supportsService( const OUString& ServiceName )
|
|
{
|
|
return cppu::supportsService( this, ServiceName );
|
|
}
|
|
|
|
uno::Sequence< OUString > SAL_CALL AccessibleBase::getSupportedServiceNames()
|
|
{
|
|
return {
|
|
"com.sun.star.accessibility.Accessible",
|
|
"com.sun.star.accessibility.AccessibleContext"
|
|
};
|
|
}
|
|
|
|
// ________ AccessibleBase::XEventListener ________
|
|
void SAL_CALL AccessibleBase::disposing( const lang::EventObject& /*Source*/ )
|
|
{
|
|
}
|
|
|
|
// ________ XAccessibleEventBroadcasters ________
|
|
void SAL_CALL AccessibleBase::addAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener )
|
|
{
|
|
MutexGuard aGuard( m_aMutex );
|
|
|
|
if ( xListener.is() )
|
|
{
|
|
if ( !m_nEventNotifierId )
|
|
m_nEventNotifierId = ::comphelper::AccessibleEventNotifier::registerClient();
|
|
|
|
::comphelper::AccessibleEventNotifier::addEventListener( m_nEventNotifierId, xListener );
|
|
}
|
|
}
|
|
|
|
void SAL_CALL AccessibleBase::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener )
|
|
{
|
|
MutexGuard aGuard( m_aMutex );
|
|
|
|
if ( xListener.is() && m_nEventNotifierId)
|
|
{
|
|
sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( m_nEventNotifierId, xListener );
|
|
if ( !nListenerCount )
|
|
{
|
|
// no listeners anymore
|
|
::comphelper::AccessibleEventNotifier::revokeClient( m_nEventNotifierId );
|
|
m_nEventNotifierId = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace chart
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|