diff options
Diffstat (limited to 'sw/source/core/access')
49 files changed, 17722 insertions, 0 deletions
diff --git a/sw/source/core/access/acccell.cxx b/sw/source/core/access/acccell.cxx new file mode 100644 index 000000000000..dbd1b5196593 --- /dev/null +++ b/sw/source/core/access/acccell.cxx @@ -0,0 +1,378 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <osl/mutex.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <rtl/uuid.h> +#include <vcl/svapp.hxx> +#include <cellfrm.hxx> +#include <tabfrm.hxx> +#include <swtable.hxx> +#include "crsrsh.hxx" +#include "viscrs.hxx" +#include <accfrmobj.hxx> +#include <accfrmobjslist.hxx> +#include "frmfmt.hxx" +#include "cellatr.hxx" +#include "accmap.hxx" +#include <acccell.hxx> + +#ifndef _STLP_CFLOAT +#include <cfloat> +#endif + +#include <limits.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; +using namespace sw::access; + +const sal_Char sServiceName[] = "com.sun.star.table.AccessibleCellView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleCellView"; + +sal_Bool SwAccessibleCell::IsSelected() +{ + sal_Bool bRet = sal_False; + + DBG_ASSERT( GetMap(), "no map?" ); + const ViewShell *pVSh = GetMap()->GetShell(); + DBG_ASSERT( pVSh, "no shell?" ); + if( pVSh->ISA( SwCrsrShell ) ) + { + const SwCrsrShell *pCSh = static_cast< const SwCrsrShell * >( pVSh ); + if( pCSh->IsTableMode() ) + { + const SwCellFrm *pCFrm = + static_cast< const SwCellFrm * >( GetFrm() ); + SwTableBox *pBox = + const_cast< SwTableBox *>( pCFrm->GetTabBox() ); //SVPtrArr! + bRet = pCSh->GetTableCrsr()->GetBoxes().Seek_Entry( pBox ); + } + } + + return bRet; +} + +void SwAccessibleCell::GetStates( ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SwAccessibleContext::GetStates( rStateSet ); + + // SELECTABLE + const ViewShell *pVSh = GetMap()->GetShell(); + DBG_ASSERT( pVSh, "no shell?" ); + if( pVSh->ISA( SwCrsrShell ) ) + rStateSet.AddState( AccessibleStateType::SELECTABLE ); + + // SELECTED + if( IsSelected() ) + { + rStateSet.AddState( AccessibleStateType::SELECTED ); + OSL_ENSURE( bIsSelected, "bSelected out of sync" ); + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } +} + +SwAccessibleCell::SwAccessibleCell( SwAccessibleMap *pInitMap, + const SwCellFrm *pCellFrm ) + : SwAccessibleContext( pInitMap, AccessibleRole::TABLE_CELL, pCellFrm ) + , bIsSelected( sal_False ) +{ + SolarMutexGuard aGuard; + OUString sBoxName( pCellFrm->GetTabBox()->GetName() ); + SetName( sBoxName ); + + bIsSelected = IsSelected(); +} + +sal_Bool SwAccessibleCell::_InvalidateMyCursorPos() +{ + sal_Bool bNew = IsSelected(); + sal_Bool bOld; + { + osl::MutexGuard aGuard( aMutex ); + bOld = bIsSelected; + bIsSelected = bNew; + } + if( bNew ) + { + // remember that object as the one that has the caret. This is + // neccessary to notify that object if the cursor leaves it. + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } + + sal_Bool bChanged = bOld != bNew; + if( bChanged ) + FireStateChangedEvent( AccessibleStateType::SELECTED, bNew ); + + return bChanged; +} + +sal_Bool SwAccessibleCell::_InvalidateChildrenCursorPos( const SwFrm *pFrm ) +{ + sal_Bool bChanged = sal_False; + + const SwAccessibleChildSList aVisList( GetVisArea(), *pFrm, *GetMap() ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm *pLower = rLower.GetSwFrm(); + if( pLower ) + { + if( rLower.IsAccessible( GetMap()->GetShell()->IsPreView() ) ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl( + GetMap()->GetContextImpl( pLower, sal_False ) ); + if( xAccImpl.is() ) + { + OSL_ENSURE( xAccImpl->GetFrm()->IsCellFrm(), + "table child is not a cell frame" ); + bChanged |= static_cast< SwAccessibleCell *>( + xAccImpl.get() )->_InvalidateMyCursorPos(); + } + else + bChanged = sal_True; // If the context is not know we + // don't know whether the selection + // changed or not. + } + else + { + // This is a box with sub rows. + bChanged |= _InvalidateChildrenCursorPos( pLower ); + } + } + ++aIter; + } + + return bChanged; +} + +void SwAccessibleCell::_InvalidateCursorPos() +{ + + const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); + OSL_ENSURE( pParent->IsTabFrm(), "parent is not a tab frame" ); + const SwTabFrm *pTabFrm = static_cast< const SwTabFrm * >( pParent ); + if( pTabFrm->IsFollow() ) + pTabFrm = pTabFrm->FindMaster(); + + while( pTabFrm ) + { + sal_Bool bChanged = _InvalidateChildrenCursorPos( pTabFrm ); + if( bChanged ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl( + GetMap()->GetContextImpl( pTabFrm, sal_False ) ); + if( xAccImpl.is() ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; + xAccImpl->FireAccessibleEvent( aEvent ); + } + } + + pTabFrm = pTabFrm->GetFollow(); + } +} + +sal_Bool SwAccessibleCell::HasCursor() +{ + osl::MutexGuard aGuard( aMutex ); + return bIsSelected; +} + +SwAccessibleCell::~SwAccessibleCell() +{ +} + +OUString SAL_CALL SwAccessibleCell::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + return GetName(); +} + +OUString SAL_CALL SwAccessibleCell::getImplementationName() + throw( uno::RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleCell::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +uno::Sequence< OUString > SAL_CALL SwAccessibleCell::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +void SwAccessibleCell::Dispose( sal_Bool bRecursive ) +{ + const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); + ::rtl::Reference< SwAccessibleContext > xAccImpl( + GetMap()->GetContextImpl( pParent, sal_False ) ); + if( xAccImpl.is() ) + xAccImpl->DisposeChild( SwAccessibleChild(GetFrm()), bRecursive ); + SwAccessibleContext::Dispose( bRecursive ); +} + +void SwAccessibleCell::InvalidatePosOrSize( const SwRect& rOldBox ) +{ + const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() ); + ::rtl::Reference< SwAccessibleContext > xAccImpl( + GetMap()->GetContextImpl( pParent, sal_False ) ); + if( xAccImpl.is() ) + xAccImpl->InvalidateChildPosOrSize( SwAccessibleChild(GetFrm()), rOldBox ); + SwAccessibleContext::InvalidatePosOrSize( rOldBox ); +} + + +// ===== XAccessibleInterface =========================================== + +uno::Any SwAccessibleCell::queryInterface( const uno::Type& rType ) + throw( uno::RuntimeException ) +{ + if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ) ) + { + uno::Reference<XAccessibleValue> xValue = this; + uno::Any aRet; + aRet <<= xValue; + return aRet; + } + else + { + return SwAccessibleContext::queryInterface( rType ); + } +} + +//====== XTypeProvider ==================================================== +uno::Sequence< uno::Type > SAL_CALL SwAccessibleCell::getTypes() + throw(uno::RuntimeException) +{ + uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); + + sal_Int32 nIndex = aTypes.getLength(); + aTypes.realloc( nIndex + 1 ); + + uno::Type* pTypes = aTypes.getArray(); + pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ); + + return aTypes; +} + +uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleCell::getImplementationId() + throw(uno::RuntimeException) +{ + SolarMutexGuard aGuard; + static uno::Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +// ===== XAccessibleValue =============================================== + +SwFrmFmt* SwAccessibleCell::GetTblBoxFormat() const +{ + DBG_ASSERT( GetFrm() != NULL, "no frame?" ); + DBG_ASSERT( GetFrm()->IsCellFrm(), "no cell frame?" ); + + const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() ); + return pCellFrm->GetTabBox()->GetFrmFmt(); +} + + +uno::Any SwAccessibleCell::getCurrentValue( ) + throw( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleValue ); + + uno::Any aAny; + aAny <<= GetTblBoxFormat()->GetTblBoxValue().GetValue(); + return aAny; +} + +sal_Bool SwAccessibleCell::setCurrentValue( const uno::Any& aNumber ) + throw( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleValue ); + + double fValue = 0; + sal_Bool bValid = (aNumber >>= fValue); + if( bValid ) + { + SwTblBoxValue aValue( fValue ); + GetTblBoxFormat()->SetFmtAttr( aValue ); + } + return bValid; +} + +uno::Any SwAccessibleCell::getMaximumValue( ) + throw( uno::RuntimeException ) +{ + uno::Any aAny; + aAny <<= DBL_MAX; + return aAny; +} + +uno::Any SwAccessibleCell::getMinimumValue( ) + throw( uno::RuntimeException ) +{ + uno::Any aAny; + aAny <<= -DBL_MAX; + return aAny; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acccell.hxx b/sw/source/core/access/acccell.hxx new file mode 100644 index 000000000000..0983f8ccc4d1 --- /dev/null +++ b/sw/source/core/access/acccell.hxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCCELL_HXX +#define _ACCCELL_HXX + +#include "acccontext.hxx" +#include <com/sun/star/accessibility/XAccessibleValue.hpp> + +class SwCellFrm; +class SwFrmFmt; + +class SwAccessibleCell : public SwAccessibleContext, + ::com::sun::star::accessibility::XAccessibleValue + +{ + sal_Bool bIsSelected; // protected by base class mutex + + sal_Bool IsSelected(); + + sal_Bool _InvalidateMyCursorPos(); + sal_Bool _InvalidateChildrenCursorPos( const SwFrm *pFrm ); + +protected: + + // Set states for getAccessibleStateSet. + // This drived class additionaly sets SELECTABLE(1) and SELECTED(+) + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + virtual void _InvalidateCursorPos(); + + virtual ~SwAccessibleCell(); + +public: + + SwAccessibleCell( SwAccessibleMap* pInitMap, const SwCellFrm *pCellFrm ); + + virtual sal_Bool HasCursor(); // required by map to remember that object + + //===== XAccessibleContext ============================================== + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + virtual void Dispose( sal_Bool bRecursive = sal_False ); + + virtual void InvalidatePosOrSize( const SwRect& rFrm ); + + //===== XInterface ====================================================== + + // (XInterface methods need to be implemented to disambiguate + // between those inherited through SwAcessibleContext and + // XAccessibleValue). + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire( ) throw () + { SwAccessibleContext::acquire(); }; + + virtual void SAL_CALL release( ) throw () + { SwAccessibleContext::release(); }; + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + //===== XAccessibleValue ================================================ + +private: + SwFrmFmt* GetTblBoxFormat() const; + +public: + virtual ::com::sun::star::uno::Any SAL_CALL getCurrentValue( ) + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL setCurrentValue( + const ::com::sun::star::uno::Any& aNumber ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Any SAL_CALL getMaximumValue( ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Any SAL_CALL getMinimumValue( ) + throw (::com::sun::star::uno::RuntimeException); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acccontext.cxx b/sw/source/core/access/acccontext.cxx new file mode 100644 index 000000000000..f8820f56039a --- /dev/null +++ b/sw/source/core/access/acccontext.cxx @@ -0,0 +1,1584 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#if (OSL_DEBUG_LEVEL > 1) && defined TEST_MIB + #ifndef _STRING_HXX + #include <tools/string.hxx> + #endif + + #ifndef _STREAM_HXX + #include <tools/stream.hxx> + #endif +#endif // #if (OSL_DEBUG_LEVEL > 1) && defined TEST_MIB +#include <tools/debug.hxx> +#include <vcl/window.hxx> +#include <swtypes.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <viewsh.hxx> +#include <crsrsh.hxx> +#include <fesh.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <pagefrm.hxx> +#include <flyfrm.hxx> +#include <dflyobj.hxx> +#include <pam.hxx> +#include <viewimp.hxx> +#include <accmap.hxx> +#include <accfrmobjslist.hxx> +#include <acccontext.hxx> +#include <svx/AccessibleShape.hxx> +#include <comphelper/accessibleeventnotifier.hxx> +#include <PostItMgr.hxx> + +using namespace sw::access; + +#if (OSL_DEBUG_LEVEL > 1) && defined TEST_MIB +#define DBG_MSG( _msg ) \ + lcl_SwAccessibleContext_DbgMsg( this, _msg, 0, sal_False ); +#define DBG_MSG_CD( _msg ) \ + lcl_SwAccessibleContext_DbgMsg( this, _msg, 0, sal_True ); +#define DBG_MSG_PARAM( _msg, _param ) \ + lcl_SwAccessibleContext_DbgMsg( this, _msg, _param, sal_False ); +#define DBG_MSG_THIS_PARAM( _msg, _this, _param ) \ + lcl_SwAccessibleContext_DbgMsg( _this, _msg, _param, sal_False ); + +void lcl_SwAccessibleContext_DbgMsg( SwAccessibleContext *pThisAcc, + const char *pMsg, + SwAccessibleContext *pChildAcc, + sal_Bool bConstrDestr ); +#else +#define DBG_MSG( _msg ) +#define DBG_MSG_PARAM( _msg, _param ) +#define DBG_MSG_THIS_PARAM( _msg, _this, _param ) +#define DBG_MSG_CD( _msg ) +#endif + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +void SwAccessibleContext::InitStates() +{ + bIsShowingState = GetMap() ? IsShowing( *(GetMap()) ) : sal_False; + + ViewShell *pVSh = GetMap()->GetShell(); + bIsEditableState = pVSh && IsEditable( pVSh ); + bIsOpaqueState = pVSh && IsOpaque( pVSh ); + bIsDefuncState = sal_False; +} + +void SwAccessibleContext::SetParent( SwAccessibleContext *pParent ) +{ + osl::MutexGuard aGuard( aMutex ); + + uno::Reference < XAccessible > xParent( pParent ); + xWeakParent = xParent; +} + +uno::Reference< XAccessible > SwAccessibleContext::GetWeakParent() const +{ + osl::MutexGuard aGuard( aMutex ); + + uno::Reference< XAccessible > xParent( xWeakParent ); + return xParent; +} + +Window *SwAccessibleContext::GetWindow() +{ + Window *pWin = 0; + + if( GetMap() ) + { + const ViewShell *pVSh = GetMap()->GetShell(); + OSL_ENSURE( pVSh, "no view shell" ); + if( pVSh ) + pWin = pVSh->GetWin(); + + OSL_ENSURE( pWin, "no window" ); + } + + return pWin; +} + +// get ViewShell from accessibility map, and cast to cursor shell +SwCrsrShell* SwAccessibleContext::GetCrsrShell() +{ + SwCrsrShell* pCrsrShell; + ViewShell* pViewShell = GetMap() ? GetMap()->GetShell() : 0; + OSL_ENSURE( pViewShell, "no view shell" ); + if( pViewShell && pViewShell->ISA( SwCrsrShell ) ) + pCrsrShell = static_cast<SwCrsrShell*>( pViewShell ); + else + pCrsrShell = NULL; + + return pCrsrShell; +} + +const SwCrsrShell* SwAccessibleContext::GetCrsrShell() const +{ + // just like non-const GetCrsrShell + const SwCrsrShell* pCrsrShell; + const ViewShell* pViewShell = GetMap() ? GetMap()->GetShell() : 0; + OSL_ENSURE( pViewShell, "no view shell" ); + if( pViewShell && pViewShell->ISA( SwCrsrShell ) ) + pCrsrShell = static_cast<const SwCrsrShell*>( pViewShell ); + else + pCrsrShell = NULL; + + return pCrsrShell; +} + + +enum Action { NONE, SCROLLED, SCROLLED_WITHIN, + SCROLLED_IN, SCROLLED_OUT }; + +void SwAccessibleContext::ChildrenScrolled( const SwFrm *pFrm, + const SwRect& rOldVisArea ) +{ + const SwRect& rNewVisArea = GetVisArea(); + const bool bVisibleChildrenOnly = SwAccessibleChild( pFrm ).IsVisibleChildrenOnly(); + + const SwAccessibleChildSList aList( *pFrm, *(GetMap()) ); + SwAccessibleChildSList::const_iterator aIter( aList.begin() ); + while( aIter != aList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + const SwRect aBox( rLower.GetBox( *(GetMap()) ) ); + if( rLower.IsAccessible( GetShell()->IsPreView() ) ) + { + Action eAction = NONE; + if( aBox.IsOver( rNewVisArea ) ) + { + if( aBox.IsOver( rOldVisArea ) ) + { + eAction = SCROLLED_WITHIN; + } + else + { + if ( bVisibleChildrenOnly && + !rLower.AlwaysIncludeAsChild() ) + { + eAction = SCROLLED_IN; + } + else + { + eAction = SCROLLED; + } + } + } + else if( aBox.IsOver( rOldVisArea ) ) + { + if ( bVisibleChildrenOnly && + !rLower.AlwaysIncludeAsChild() ) + { + eAction = SCROLLED_OUT; + } + else + { + eAction = SCROLLED; + } + } + else if( !bVisibleChildrenOnly || + rLower.AlwaysIncludeAsChild() ) + { + // This wouldn't be required if the SwAccessibleFrame, + // wouldn't know about the vis area. + eAction = SCROLLED; + } + if( NONE != eAction ) + { + if ( rLower.GetSwFrm() ) + { + OSL_ENSURE( !rLower.AlwaysIncludeAsChild(), + "<SwAccessibleContext::ChildrenScrolled(..)> - always included child not considered!" ); + const SwFrm* pLower( rLower.GetSwFrm() ); + ::rtl::Reference< SwAccessibleContext > xAccImpl = + GetMap()->GetContextImpl( pLower, SCROLLED_OUT == eAction || + SCROLLED_IN == eAction ); + if( xAccImpl.is() ) + { + switch( eAction ) + { + case SCROLLED: + xAccImpl->Scrolled( rOldVisArea ); + break; + case SCROLLED_WITHIN: + xAccImpl->ScrolledWithin( rOldVisArea ); + break; + case SCROLLED_IN: + xAccImpl->ScrolledIn(); + break; + case SCROLLED_OUT: + xAccImpl->ScrolledOut( rOldVisArea ); + break; + case NONE: + break; + } + } + else + { + ChildrenScrolled( pLower, rOldVisArea ); + } + } + else if ( rLower.GetDrawObject() ) + { + OSL_ENSURE( !rLower.AlwaysIncludeAsChild(), + "<SwAccessibleContext::ChildrenScrolled(..)> - always included child not considered!" ); + ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl = + GetMap()->GetContextImpl( rLower.GetDrawObject(), + this, + SCROLLED_OUT == eAction || + SCROLLED_IN == eAction ); + if( xAccImpl.is() ) + { + switch( eAction ) + { + case SCROLLED: + case SCROLLED_WITHIN: + xAccImpl->ViewForwarderChanged( + ::accessibility::IAccessibleViewForwarderListener::VISIBLE_AREA, + GetMap() ); + break; + case SCROLLED_IN: + ScrolledInShape( rLower.GetDrawObject(), + xAccImpl.get() ); + break; + case SCROLLED_OUT: + { + xAccImpl->ViewForwarderChanged( + ::accessibility::IAccessibleViewForwarderListener::VISIBLE_AREA, + GetMap() ); + DisposeShape( rLower.GetDrawObject(), + xAccImpl.get() ); + } + break; + case NONE: + break; + } + } + } + else if ( rLower.GetWindow() ) + { + // nothing to do - as such children are always included as children. + OSL_ENSURE( rLower.AlwaysIncludeAsChild(), + "<SwAccessibleContext::ChildrenScrolled(..)> - not always included child not considered!" ); + } + } + } + else if ( rLower.GetSwFrm() && + ( !bVisibleChildrenOnly || + aBox.IsOver( rOldVisArea ) || + aBox.IsOver( rNewVisArea ) ) ) + { + // There are no unaccessible SdrObjects that need to be notified + ChildrenScrolled( rLower.GetSwFrm(), rOldVisArea ); + } + ++aIter; + } +} + +void SwAccessibleContext::Scrolled( const SwRect& rOldVisArea ) +{ + SetVisArea( GetMap()->GetVisArea() ); + + ChildrenScrolled( GetFrm(), rOldVisArea ); + + sal_Bool bIsOldShowingState; + sal_Bool bIsNewShowingState = IsShowing( *(GetMap()) ); + { + osl::MutexGuard aGuard( aMutex ); + bIsOldShowingState = bIsShowingState; + bIsShowingState = bIsNewShowingState; + } + + if( bIsOldShowingState != bIsNewShowingState ) + FireStateChangedEvent( AccessibleStateType::SHOWING, + bIsNewShowingState ); +} + +void SwAccessibleContext::ScrolledWithin( const SwRect& rOldVisArea ) +{ + SetVisArea( GetMap()->GetVisArea() ); + + ChildrenScrolled( GetFrm(), rOldVisArea ); + + FireVisibleDataEvent(); +} + +void SwAccessibleContext::ScrolledIn() +{ + // This accessible should be freshly created, because it + // was not visisble before. Therefor, its vis area must already + // reflect the scrolling. + OSL_ENSURE( GetVisArea() == GetMap()->GetVisArea(), + "Vis area of child is wrong. Did it exist already?" ); + + // Send child event at parent. That's all we have to do here. + const SwFrm* pParent = GetParent(); + ::rtl::Reference< SwAccessibleContext > xParentImpl( + GetMap()->GetContextImpl( pParent, sal_False ) ); + uno::Reference < XAccessibleContext > xThis( this ); + if( xParentImpl.is() ) + { + SetParent( xParentImpl.get() ); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= xThis; + + xParentImpl->FireAccessibleEvent( aEvent ); + DBG_MSG_PARAM( "AccessibleChild (added)", xChildImpl.get() ); + + if( HasCursor() ) + { + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() ) + { + FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True ); + } + } + + } +} + +void SwAccessibleContext::ScrolledOut( const SwRect& rOldVisArea ) +{ + SetVisArea( GetMap()->GetVisArea() ); + + // First of all, update the children. That's required to dispose + // all children that are existing only if they are visible. They + // are not disposed by the recusive Dispose call that follows later on, + // because this call will only dispose children that are in the + // new vis area. The children we want to dispode however are in the + // old vis area all. + ChildrenScrolled( GetFrm(), rOldVisArea ); + + // Broadcast a state changed event for the showing state. + // It might be that the child is freshly created just to send + // the child event. In this case no listener will exist. + FireStateChangedEvent( AccessibleStateType::SHOWING, sal_False ); + + // We now dispose the frame + Dispose( sal_True ); +} + +// #i27301# - use new type definition for <_nStates> +void SwAccessibleContext::InvalidateChildrenStates( const SwFrm* _pFrm, + tAccessibleStates _nStates ) +{ + const SwAccessibleChildSList aVisList( GetVisArea(), *_pFrm, *(GetMap()) ); + + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm* pLower = rLower.GetSwFrm(); + if( pLower ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl; + if( rLower.IsAccessible( GetShell()->IsPreView() ) ) + xAccImpl = GetMap()->GetContextImpl( pLower, sal_False ); + if( xAccImpl.is() ) + xAccImpl->InvalidateStates( _nStates ); + else + InvalidateChildrenStates( pLower, _nStates ); + } + else if ( rLower.GetDrawObject() ) + { + // TODO: SdrObjects + } + else if ( rLower.GetWindow() ) + { + // nothing to do ? + } + + ++aIter; + } +} +// <-- + +void SwAccessibleContext::DisposeChildren( const SwFrm *pFrm, + sal_Bool bRecursive ) +{ + const SwAccessibleChildSList aVisList( GetVisArea(), *pFrm, *(GetMap()) ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm* pLower = rLower.GetSwFrm(); + if( pLower ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl; + if( rLower.IsAccessible( GetShell()->IsPreView() ) ) + xAccImpl = GetMap()->GetContextImpl( pLower, sal_False ); + if( xAccImpl.is() ) + xAccImpl->Dispose( bRecursive ); + else if( bRecursive ) + DisposeChildren( pLower, bRecursive ); + } + else if ( rLower.GetDrawObject() ) + { + ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl( + GetMap()->GetContextImpl( rLower.GetDrawObject(), + this, sal_False ) ); + if( xAccImpl.is() ) + DisposeShape( rLower.GetDrawObject(), xAccImpl.get() ); + } + else if ( rLower.GetWindow() ) + { + DisposeChild( rLower, sal_False ); + } + ++aIter; + } +} + +void SwAccessibleContext::_InvalidateContent( sal_Bool ) +{ +} + +void SwAccessibleContext::_InvalidateCursorPos() +{ +} + +void SwAccessibleContext::_InvalidateFocus() +{ +} + +void SwAccessibleContext::FireAccessibleEvent( AccessibleEventObject& rEvent ) +{ + OSL_ENSURE( GetFrm(), "fire event for diposed frame?" ); + if( !GetFrm() ) + return; + + if( !rEvent.Source.is() ) + { + uno::Reference < XAccessibleContext > xThis( this ); + rEvent.Source = xThis; + } + + if (nClientId) + comphelper::AccessibleEventNotifier::addEvent( nClientId, rEvent ); +} + +void SwAccessibleContext::FireVisibleDataEvent() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; + + FireAccessibleEvent( aEvent ); + DBG_MSG( "AccessibleVisibleData" ) +} + +void SwAccessibleContext::FireStateChangedEvent( sal_Int16 nState, + sal_Bool bNewState ) +{ + AccessibleEventObject aEvent; + + aEvent.EventId = AccessibleEventId::STATE_CHANGED; + if( bNewState ) + aEvent.NewValue <<= nState; + else + aEvent.OldValue <<= nState; + + FireAccessibleEvent( aEvent ); + DBG_MSG( "StateChanged" ) +} + +void SwAccessibleContext::GetStates( + ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SolarMutexGuard aGuard; + + // SHOWING + if( bIsShowingState ) + rStateSet.AddState( AccessibleStateType::SHOWING ); + + // EDITABLE + if( bIsEditableState ) + rStateSet.AddState( AccessibleStateType::EDITABLE ); + + // ENABLED + rStateSet.AddState( AccessibleStateType::ENABLED ); + + // OPAQUE + if( bIsOpaqueState ) + rStateSet.AddState( AccessibleStateType::OPAQUE ); + + // VISIBLE + rStateSet.AddState( AccessibleStateType::VISIBLE ); + + if( bIsDefuncState ) + rStateSet.AddState( AccessibleStateType::DEFUNC ); +} + +sal_Bool SwAccessibleContext::IsEditableState() +{ + sal_Bool bRet; + { + osl::MutexGuard aGuard( aMutex ); + bRet = bIsEditableState; + } + + return bRet; +} + +SwAccessibleContext::SwAccessibleContext( SwAccessibleMap *pM, + sal_Int16 nR, + const SwFrm *pF ) + : SwAccessibleFrame( pM->GetVisArea().SVRect(), pF, + pM->GetShell()->IsPreView() ) + , pMap( pM ) + , nClientId(0) + , nRole( nR ) + , bDisposing( sal_False ) + , bRegisteredAtAccessibleMap( true ) +{ + InitStates(); + DBG_MSG_CD( "constructed" ) +} + +SwAccessibleContext::~SwAccessibleContext() +{ + SolarMutexGuard aGuard; + + DBG_MSG_CD( "destructed" ) + RemoveFrmFromAccessibleMap(); +} + +uno::Reference< XAccessibleContext > SAL_CALL + SwAccessibleContext::getAccessibleContext( void ) + throw (uno::RuntimeException) +{ + uno::Reference < XAccessibleContext > xRet( this ); + return xRet; +} + +sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleChildCount( void ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + return bDisposing ? 0 : GetChildCount( *(GetMap()) ); +} + +uno::Reference< XAccessible> SAL_CALL + SwAccessibleContext::getAccessibleChild( sal_Int32 nIndex ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + const SwAccessibleChild aChild( GetChild( *(GetMap()), nIndex ) ); + if( !aChild.IsValid() ) + { + uno::Reference < XAccessibleContext > xThis( this ); + lang::IndexOutOfBoundsException aExcept( + OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ), + xThis ); + throw aExcept; + } + + uno::Reference< XAccessible > xChild; + if( aChild.GetSwFrm() ) + { + ::rtl::Reference < SwAccessibleContext > xChildImpl( + GetMap()->GetContextImpl( aChild.GetSwFrm(), !bDisposing ) ); + if( xChildImpl.is() ) + { + xChildImpl->SetParent( this ); + xChild = xChildImpl.get(); + } + } + else if ( aChild.GetDrawObject() ) + { + ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl( + GetMap()->GetContextImpl( aChild.GetDrawObject(), + this, !bDisposing ) ); + if( xChildImpl.is() ) + xChild = xChildImpl.get(); + } + else if ( aChild.GetWindow() ) + { + xChild = aChild.GetWindow()->GetAccessible(); + } + + return xChild; +} + +uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParent (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + const SwFrm *pUpper = GetParent(); + OSL_ENSURE( pUpper != 0 || bDisposing, "no upper found" ); + + uno::Reference< XAccessible > xAcc; + if( pUpper ) + xAcc = GetMap()->GetContext( pUpper, !bDisposing ); + + OSL_ENSURE( xAcc.is() || bDisposing, "no parent found" ); + + // Remember the parent as weak ref. + { + osl::MutexGuard aWeakParentGuard( aMutex ); + xWeakParent = xAcc; + } + + return xAcc; +} + +sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleIndexInParent (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + const SwFrm *pUpper = GetParent(); + OSL_ENSURE( pUpper != 0 || bDisposing, "no upper found" ); + + sal_Int32 nIndex = -1; + if( pUpper ) + { + ::rtl::Reference < SwAccessibleContext > xAccImpl( + GetMap()->GetContextImpl( pUpper, !bDisposing ) ); + OSL_ENSURE( xAccImpl.is() || bDisposing, "no parent found" ); + if( xAccImpl.is() ) + nIndex = xAccImpl->GetChildIndex( *(GetMap()), SwAccessibleChild(GetFrm()) ); + } + + return nIndex; +} + +sal_Int16 SAL_CALL SwAccessibleContext::getAccessibleRole (void) + throw (uno::RuntimeException) +{ + return nRole; +} + +OUString SAL_CALL SwAccessibleContext::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + OSL_ENSURE( !this, "description needs to be overloaded" ); + THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (method must be overloaded)" ); +} + +OUString SAL_CALL SwAccessibleContext::getAccessibleName (void) + throw (uno::RuntimeException) +{ + return sName; +} + +uno::Reference< XAccessibleRelationSet> SAL_CALL + SwAccessibleContext::getAccessibleRelationSet (void) + throw (uno::RuntimeException) +{ + // by default there are no relations + uno::Reference< XAccessibleRelationSet> xRet( new utl::AccessibleRelationSetHelper() ); + return xRet; +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + SwAccessibleContext::getAccessibleStateSet (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + ::utl::AccessibleStateSetHelper *pStateSet = + new ::utl::AccessibleStateSetHelper; + + uno::Reference<XAccessibleStateSet> xStateSet( pStateSet ); + GetStates( *pStateSet ); + + return xStateSet; +} + +lang::Locale SAL_CALL SwAccessibleContext::getLocale (void) + throw (IllegalAccessibleComponentStateException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + lang::Locale aLoc( Application::GetSettings().GetLocale() ); + return aLoc; +} + +void SAL_CALL SwAccessibleContext::addEventListener( + const uno::Reference< XAccessibleEventListener >& xListener ) + throw (uno::RuntimeException) +{ + DBG_MSG( "accessible event listener added" ) + + if (xListener.is()) + { + SolarMutexGuard aGuard; + if (!nClientId) + nClientId = comphelper::AccessibleEventNotifier::registerClient( ); + comphelper::AccessibleEventNotifier::addEventListener( nClientId, xListener ); + } +} + +void SAL_CALL SwAccessibleContext::removeEventListener( + const uno::Reference< XAccessibleEventListener >& xListener ) + throw (uno::RuntimeException) +{ + DBG_MSG( "accessible event listener removed" ) + + if (xListener.is()) + { + SolarMutexGuard aGuard; + sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( nClientId, xListener ); + if ( !nListenerCount ) + { + // no listeners anymore + // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), + // and at least to us not firing any events anymore, in case somebody calls + // NotifyAccessibleEvent, again + comphelper::AccessibleEventNotifier::revokeClient( nClientId ); + nClientId = 0; + } + } +} + +static sal_Bool lcl_PointInRectangle(const awt::Point & aPoint, + const awt::Rectangle & aRect) +{ + long nDiffX = aPoint.X - aRect.X; + long nDiffY = aPoint.Y - aRect.Y; + + return + nDiffX >= 0 && nDiffX < aRect.Width && nDiffY >= 0 && + nDiffY < aRect.Height; + +} + +sal_Bool SAL_CALL SwAccessibleContext::containsPoint( + const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + awt::Rectangle aPixBounds = getBoundsImpl(sal_True); + aPixBounds.X = 0; + aPixBounds.Y = 0; + + return lcl_PointInRectangle(aPoint, aPixBounds); +} + +uno::Reference< XAccessible > SAL_CALL SwAccessibleContext::getAccessibleAtPoint( + const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleComponent ) + + uno::Reference< XAccessible > xAcc; + + Window *pWin = GetWindow(); + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Point aPixPoint( aPoint.X, aPoint.Y ); // px rel to parent + if( !GetFrm()->IsRootFrm() ) + { + SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root + Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() ); + aPixPoint.X() += aPixPos.X(); + aPixPoint.Y() += aPixPos.Y(); + } + + const SwAccessibleChild aChild( GetChildAtPixel( aPixPoint, *(GetMap()) ) ); + if( aChild.GetSwFrm() ) + { + xAcc = GetMap()->GetContext( aChild.GetSwFrm() ); + } + else if( aChild.GetDrawObject() ) + { + xAcc = GetMap()->GetContext( aChild.GetDrawObject(), this ); + } + else if ( aChild.GetWindow() ) + { + xAcc = aChild.GetWindow()->GetAccessible(); + } + + return xAcc; +} + + +/** + Get bounding box. + + There are two modes. + + - realative + + Return bounding box relative to parent if parent is no root + frame. Otherwise return the absolute bounding box. + + - absolute + + Return the absolute bounding box. + + @param bRelative + true: Use relative mode. + false: Use absolute mode. +*/ +awt::Rectangle SAL_CALL SwAccessibleContext::getBoundsImpl(sal_Bool bRelative) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleComponent ) + + const SwFrm *pParent = GetParent(); + OSL_ENSURE( pParent, "no Parent found" ); + Window *pWin = GetWindow(); + + CHECK_FOR_WINDOW( XAccessibleComponent, pWin && pParent ) + + SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root + Rectangle aPixBounds( 0, 0, 0, 0 ); + if( GetFrm()->IsPageFrm() && + static_cast < const SwPageFrm * >( GetFrm() )->IsEmptyPage() ) + { + OSL_ENSURE( GetShell()->IsPreView(), "empty page accessible?" ); + if( GetShell()->IsPreView() ) + { + // adjust method call <GetMap()->GetPreViewPageSize()> + sal_uInt16 nPageNum = + static_cast < const SwPageFrm * >( GetFrm() )->GetPhyPageNum(); + aLogBounds.SSize( GetMap()->GetPreViewPageSize( nPageNum ) ); + } + } + if( !aLogBounds.IsEmpty() ) + { + aPixBounds = GetMap()->CoreToPixel( aLogBounds.SVRect() ); + if( !pParent->IsRootFrm() && bRelative) + { + SwRect aParentLogBounds( GetBounds( *(GetMap()), pParent ) ); // twip rel to doc root + Point aParentPixPos( GetMap()->CoreToPixel( aParentLogBounds.SVRect() ).TopLeft() ); + aPixBounds.Move( -aParentPixPos.X(), -aParentPixPos.Y() ); + } + } + + awt::Rectangle aBox( aPixBounds.Left(), aPixBounds.Top(), + aPixBounds.GetWidth(), aPixBounds.GetHeight() ); + + return aBox; +} + + +awt::Rectangle SAL_CALL SwAccessibleContext::getBounds() + throw (uno::RuntimeException) +{ + return getBoundsImpl(sal_True); +} + +awt::Point SAL_CALL SwAccessibleContext::getLocation() + throw (uno::RuntimeException) +{ + awt::Rectangle aRect = getBoundsImpl(sal_True); + awt::Point aPoint(aRect.X, aRect.Y); + + return aPoint; +} + + + +awt::Point SAL_CALL SwAccessibleContext::getLocationOnScreen() + throw (uno::RuntimeException) +{ + awt::Rectangle aRect = getBoundsImpl(sal_False); + + Point aPixPos(aRect.X, aRect.Y); + + /* getBoundsImpl already checked that GetWindow returns valid pointer. */ + aPixPos = GetWindow()->OutputToAbsoluteScreenPixel(aPixPos); + awt::Point aPoint(aPixPos.X(), aPixPos.Y()); + + return aPoint; +} + + +awt::Size SAL_CALL SwAccessibleContext::getSize() + throw (uno::RuntimeException) +{ + awt::Rectangle aRect = getBoundsImpl(sal_False); + awt::Size aSize( aRect.Width, aRect.Height ); + + return aSize; +} + +void SAL_CALL SwAccessibleContext::grabFocus() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ); + + if( GetFrm()->IsFlyFrm() ) + { + const SdrObject *pObj = + static_cast < const SwFlyFrm * >( GetFrm() )->GetVirtDrawObj(); + if( pObj ) + Select( const_cast < SdrObject * >( pObj ), sal_False ); + } + else + { + const SwCntntFrm *pCFrm = 0; + if( GetFrm()->IsCntntFrm() ) + pCFrm = static_cast< const SwCntntFrm * >( GetFrm() ); + else if( GetFrm()->IsLayoutFrm() ) + pCFrm = static_cast< const SwLayoutFrm * >( GetFrm() )->ContainsCntnt(); + + if( pCFrm && pCFrm->IsTxtFrm() ) + { + const SwTxtFrm *pTxtFrm = static_cast< const SwTxtFrm * >( pCFrm ); + const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode(); + if( pTxtNd ) + { + // create pam for selection + SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ), + pTxtFrm->GetOfst() ); + SwPosition aStartPos( *pTxtNd, aIndex ); + SwPaM aPaM( aStartPos ); + + // set PaM at cursor shell + Select( aPaM ); + } + } + } +} + + +uno::Any SAL_CALL SwAccessibleContext::getAccessibleKeyBinding() + throw (uno::RuntimeException) +{ + // There are no key bindings + return uno::Any(); +} + +sal_Int32 SAL_CALL SwAccessibleContext::getForeground() + throw (uno::RuntimeException) +{ + return 0; +} + +sal_Int32 SAL_CALL SwAccessibleContext::getBackground() + throw (uno::RuntimeException) +{ + return 0xffffff; +} + + +OUString SAL_CALL SwAccessibleContext::getImplementationName() + throw( uno::RuntimeException ) +{ + OSL_ENSURE( !this, "implementation name needs to be overloaded" ); + + THROW_RUNTIME_EXCEPTION( lang::XServiceInfo, "implementation name needs to be overloaded" ) +} + +sal_Bool SAL_CALL + SwAccessibleContext::supportsService (const ::rtl::OUString& ) + throw (uno::RuntimeException) +{ + OSL_ENSURE( !this, "supports service needs to be overloaded" ); + THROW_RUNTIME_EXCEPTION( lang::XServiceInfo, "supports service needs to be overloaded" ) +} + +uno::Sequence< OUString > SAL_CALL SwAccessibleContext::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + OSL_ENSURE( !this, "supported services names needs to be overloaded" ); + THROW_RUNTIME_EXCEPTION( lang::XServiceInfo, "supported services needs to be overloaded" ) +} + +void SwAccessibleContext::DisposeShape( const SdrObject *pObj, + ::accessibility::AccessibleShape *pAccImpl ) +{ + ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl( pAccImpl ); + if( !xAccImpl.is() ) + xAccImpl = GetMap()->GetContextImpl( pObj, this, sal_True ); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + uno::Reference< XAccessible > xAcc( xAccImpl.get() ); + aEvent.OldValue <<= xAcc; + FireAccessibleEvent( aEvent ); + + GetMap()->RemoveContext( pObj ); + xAccImpl->dispose(); +} + +void SwAccessibleContext::ScrolledInShape( const SdrObject* , + ::accessibility::AccessibleShape *pAccImpl ) +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + uno::Reference< XAccessible > xAcc( pAccImpl ); + aEvent.NewValue <<= xAcc; + FireAccessibleEvent( aEvent ); + + if( pAccImpl->GetState( AccessibleStateType::FOCUSED ) ) + { + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() ) + { + AccessibleEventObject aStateChangedEvent; + aStateChangedEvent.EventId = AccessibleEventId::STATE_CHANGED; + aStateChangedEvent.NewValue <<= AccessibleStateType::FOCUSED; + aStateChangedEvent.Source = xAcc; + + FireAccessibleEvent( aStateChangedEvent ); + } + } +} + +void SwAccessibleContext::Dispose( sal_Bool bRecursive ) +{ + SolarMutexGuard aGuard; + + OSL_ENSURE( GetFrm() && GetMap(), "already disposed" ); + OSL_ENSURE( GetMap()->GetVisArea() == GetVisArea(), + "invalid vis area for dispose" ); + + bDisposing = sal_True; + + // dispose children + if( bRecursive ) + DisposeChildren( GetFrm(), bRecursive ); + + // get parent + uno::Reference< XAccessible > xParent( GetWeakParent() ); + uno::Reference < XAccessibleContext > xThis( this ); + + // send child event at parent + if( xParent.is() ) + { + SwAccessibleContext *pAcc = (SwAccessibleContext *)xParent.get(); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.OldValue <<= xThis; + pAcc->FireAccessibleEvent( aEvent ); + DBG_MSG_THIS_PARAM( "AccessibleChild (removed)", pAcc, this ) + } + + // set defunc state (its not required to broadcast a state changed + // event if the object is diposed afterwards) + { + osl::MutexGuard aDefuncStateGuard( aMutex ); + bIsDefuncState = sal_True; + } + + // broadcast dispose event + if ( nClientId ) + { + comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, *this ); + nClientId = 0; + DBG_MSG_CD( "dispose" ) + } + + RemoveFrmFromAccessibleMap(); + ClearFrm(); + pMap = 0; + + bDisposing = sal_False; +} + +void SwAccessibleContext::DisposeChild( const SwAccessibleChild& rChildFrmOrObj, + sal_Bool bRecursive ) +{ + SolarMutexGuard aGuard; + + if ( IsShowing( *(GetMap()), rChildFrmOrObj ) || + rChildFrmOrObj.AlwaysIncludeAsChild() || + !SwAccessibleChild( GetFrm() ).IsVisibleChildrenOnly() ) + { + // If the object could have existed before, than there is nothing to do, + // because no wrapper exists now and therefor no one is interested to + // get notified of the movement. + if( rChildFrmOrObj.GetSwFrm() ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl = + GetMap()->GetContextImpl( rChildFrmOrObj.GetSwFrm(), + sal_True ); + xAccImpl->Dispose( bRecursive ); + } + else if ( rChildFrmOrObj.GetDrawObject() ) + { + ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl = + GetMap()->GetContextImpl( rChildFrmOrObj.GetDrawObject(), + this, sal_True ); + DisposeShape( rChildFrmOrObj.GetDrawObject(), + xAccImpl.get() ); + } + else if ( rChildFrmOrObj.GetWindow() ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + uno::Reference< XAccessible > xAcc = + rChildFrmOrObj.GetWindow()->GetAccessible(); + aEvent.OldValue <<= xAcc; + FireAccessibleEvent( aEvent ); + } + } + else if( bRecursive && rChildFrmOrObj.GetSwFrm() ) + DisposeChildren( rChildFrmOrObj.GetSwFrm(), bRecursive ); +} + +void SwAccessibleContext::InvalidatePosOrSize( const SwRect& ) +{ + SolarMutexGuard aGuard; + + OSL_ENSURE( GetFrm() && !GetFrm()->Frm().IsEmpty(), "context should have a size" ); + + sal_Bool bIsOldShowingState; + sal_Bool bIsNewShowingState = IsShowing( *(GetMap()) ); + { + osl::MutexGuard aShowingStateGuard( aMutex ); + bIsOldShowingState = bIsShowingState; + bIsShowingState = bIsNewShowingState; + } + + if( bIsOldShowingState != bIsNewShowingState ) + { + FireStateChangedEvent( AccessibleStateType::SHOWING, + bIsNewShowingState ); + } + else if( bIsNewShowingState ) + { + // The frame stays visible -> broadcast event + FireVisibleDataEvent(); + } + + if( !bIsNewShowingState && + SwAccessibleChild( GetParent() ).IsVisibleChildrenOnly() ) + { + // The frame is now invisible -> dispose it + Dispose( sal_True ); + } + else + { + _InvalidateContent( sal_True ); + } +} + +void SwAccessibleContext::InvalidateChildPosOrSize( + const SwAccessibleChild& rChildFrmOrObj, + const SwRect& rOldFrm ) +{ + SolarMutexGuard aGuard; + + OSL_ENSURE( !rChildFrmOrObj.GetSwFrm() || + !rChildFrmOrObj.GetSwFrm()->Frm().IsEmpty(), + "child context should have a size" ); + + if ( rChildFrmOrObj.AlwaysIncludeAsChild() ) + { + // nothing to do; + return; + } + + const bool bVisibleChildrenOnly = SwAccessibleChild( GetFrm() ).IsVisibleChildrenOnly(); + const bool bNew = rOldFrm.IsEmpty() || + ( rOldFrm.Left() == 0 && rOldFrm.Top() == 0 ); + if( IsShowing( *(GetMap()), rChildFrmOrObj ) ) + { + // If the object could have existed before, than there is nothing to do, + // because no wrapper exists now and therefor no one is interested to + // get notified of the movement. + if( bNew || (bVisibleChildrenOnly && !IsShowing( rOldFrm )) ) + { + if( rChildFrmOrObj.GetSwFrm() ) + { + // The frame becomes visible. A child event must be send. + ::rtl::Reference< SwAccessibleContext > xAccImpl = + GetMap()->GetContextImpl( rChildFrmOrObj.GetSwFrm(), + sal_True ); + xAccImpl->ScrolledIn(); + } + else if ( rChildFrmOrObj.GetDrawObject() ) + { + ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl = + GetMap()->GetContextImpl( rChildFrmOrObj.GetDrawObject(), + this, sal_True ); + // #i37790# + if ( xAccImpl.is() ) + { + ScrolledInShape( rChildFrmOrObj.GetDrawObject(), + xAccImpl.get() ); + } + else + { + OSL_FAIL( "<SwAccessibleContext::InvalidateChildPosOrSize(..)> - no accessible shape found." ); + } + // <-- + } + else if ( rChildFrmOrObj.GetWindow() ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= (rChildFrmOrObj.GetWindow()->GetAccessible()); + FireAccessibleEvent( aEvent ); + } + } + } + else + { + // If the frame was visible before, than a child event for the parent + // needs to be send. However, there is no wrapper existing, and so + // no notifications for grandchildren are required. If the are + // grandgrandchildren, they would be notified by the layout. + if( bVisibleChildrenOnly && + !bNew && IsShowing( rOldFrm ) ) + { + if( rChildFrmOrObj.GetSwFrm() ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl = + GetMap()->GetContextImpl( rChildFrmOrObj.GetSwFrm(), + sal_True ); + xAccImpl->SetParent( this ); + xAccImpl->Dispose( sal_True ); + } + else if ( rChildFrmOrObj.GetDrawObject() ) + { + ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl = + GetMap()->GetContextImpl( rChildFrmOrObj.GetDrawObject(), + this, sal_True ); + DisposeShape( rChildFrmOrObj.GetDrawObject(), + xAccImpl.get() ); + } + else if ( rChildFrmOrObj.GetWindow() ) + { + OSL_FAIL( "<SwAccessibleContext::InvalidateChildPosOrSize(..)> - not expected to handle dispose of child of type <Window>." ); + } + } + } +} + +void SwAccessibleContext::InvalidateContent() +{ + SolarMutexGuard aGuard; + + _InvalidateContent( sal_False ); +} + +void SwAccessibleContext::InvalidateCursorPos() +{ + SolarMutexGuard aGuard; + + _InvalidateCursorPos(); +} + +void SwAccessibleContext::InvalidateFocus() +{ + SolarMutexGuard aGuard; + + _InvalidateFocus(); +} + +// #i27301# - use new type definition for <_nStates> +void SwAccessibleContext::InvalidateStates( tAccessibleStates _nStates ) +{ + if( GetMap() ) + { + ViewShell *pVSh = GetMap()->GetShell(); + if( pVSh ) + { + if( (_nStates & ACC_STATE_EDITABLE) != 0 ) + { + sal_Bool bIsOldEditableState; + sal_Bool bIsNewEditableState = IsEditable( pVSh ); + { + osl::MutexGuard aGuard( aMutex ); + bIsOldEditableState = bIsEditableState; + bIsEditableState = bIsNewEditableState; + } + + if( bIsOldEditableState != bIsNewEditableState ) + FireStateChangedEvent( AccessibleStateType::EDITABLE, + bIsNewEditableState ); + } + if( (_nStates & ACC_STATE_OPAQUE) != 0 ) + { + sal_Bool bIsOldOpaqueState; + sal_Bool bIsNewOpaqueState = IsOpaque( pVSh ); + { + osl::MutexGuard aGuard( aMutex ); + bIsOldOpaqueState = bIsOpaqueState; + bIsOpaqueState = bIsNewOpaqueState; + } + + if( bIsOldOpaqueState != bIsNewOpaqueState ) + FireStateChangedEvent( AccessibleStateType::OPAQUE, + bIsNewOpaqueState ); + } + } + + InvalidateChildrenStates( GetFrm(), _nStates ); + } +} +// <-- + +void SwAccessibleContext::InvalidateRelation( sal_uInt16 nType ) +{ + AccessibleEventObject aEvent; + aEvent.EventId = nType; + + FireAccessibleEvent( aEvent ); +} + +/** #i27301# - text selection has changed */ +void SwAccessibleContext::InvalidateTextSelection() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TEXT_SELECTION_CHANGED; + + FireAccessibleEvent( aEvent ); +} + +/** #i88069# - attributes has changed */ +void SwAccessibleContext::InvalidateAttr() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TEXT_ATTRIBUTE_CHANGED; + + FireAccessibleEvent( aEvent ); +} + +sal_Bool SwAccessibleContext::HasCursor() +{ + return sal_False; +} + +sal_Bool SwAccessibleContext::Select( SwPaM *pPaM, SdrObject *pObj, + sal_Bool bAdd ) +{ + SwCrsrShell* pCrsrShell = GetCrsrShell(); + if( !pCrsrShell ) + return sal_False; + + SwFEShell* pFEShell = pCrsrShell->ISA( SwFEShell ) + ? static_cast<SwFEShell*>( pCrsrShell ) + : 0; + // Get rid of activated OLE object + if( pFEShell ) + pFEShell->FinishOLEObj(); + + sal_Bool bRet = sal_False; + if( pObj ) + { + if( pFEShell ) + { + Point aDummy; + sal_uInt8 nFlags = bAdd ? SW_ADD_SELECT : 0; + pFEShell->SelectObj( aDummy, nFlags, pObj ); + bRet = sal_True; + } + } + else if( pPaM ) + { + // Get rid of frame selection. If there is one, make text cursor + // visible again. + sal_Bool bCallShowCrsr = sal_False; + if( pFEShell && (pFEShell->IsFrmSelected() || + pFEShell->IsObjSelected()) ) + { + Point aPt( LONG_MIN, LONG_MIN ); + pFEShell->SelectObj( aPt, 0 ); + bCallShowCrsr = sal_True; + } + pCrsrShell->KillPams(); + pCrsrShell->SetSelection( *pPaM ); + if( bCallShowCrsr ) + pCrsrShell->ShowCrsr(); + bRet = sal_True; + } + + return bRet; +} + +OUString SwAccessibleContext::GetResource( sal_uInt16 nResId, + const OUString *pArg1, + const OUString *pArg2 ) +{ + String sStr; + { + SolarMutexGuard aGuard; + + sStr = SW_RES( nResId ); + } + + if( pArg1 ) + { + sStr.SearchAndReplace( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "$(ARG1)" )), + String( *pArg1 ) ); + } + if( pArg2 ) + { + sStr.SearchAndReplace( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "$(ARG2)" )), + String( *pArg2 ) ); + } + + return OUString( sStr ); +} + +void SwAccessibleContext::RemoveFrmFromAccessibleMap() +{ + if( bRegisteredAtAccessibleMap && GetFrm() && GetMap() ) + GetMap()->RemoveContext( GetFrm() ); +} + +bool SwAccessibleContext::HasAdditionalAccessibleChildren() +{ + bool bRet( false ); + + if ( GetFrm()->IsTxtFrm() ) + { + SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr(); + if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ) + { + bRet = pPostItMgr->HasFrmConnectedSidebarWins( *(GetFrm()) ); + } + } + + return bRet; +} +/** #i88070# - get additional accessible child by index */ +Window* SwAccessibleContext::GetAdditionalAccessibleChild( const sal_Int32 nIndex ) +{ + Window* pAdditionalAccessibleChild( 0 ); + + if ( GetFrm()->IsTxtFrm() ) + { + SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr(); + if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ) + { + pAdditionalAccessibleChild = + pPostItMgr->GetSidebarWinForFrmByIndex( *(GetFrm()), nIndex ); + } + } + + return pAdditionalAccessibleChild; +} + +/** #i88070# - get all additional accessible children */ +void SwAccessibleContext::GetAdditionalAccessibleChildren( std::vector< Window* >* pChildren ) +{ + if ( GetFrm()->IsTxtFrm() ) + { + SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr(); + if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ) + { + pPostItMgr->GetAllSidebarWinForFrm( *(GetFrm()), pChildren ); + } + } +} + +#if (OSL_DEBUG_LEVEL > 1) && defined TEST_MIB +void lcl_SwAccessibleContext_DbgMsg( SwAccessibleContext *pThisAcc, + const char *pMsg, + SwAccessibleContext *pChildAcc, + sal_Bool bConstrDestr ) +{ + static SvFileStream aStrm( String::CreateFromAscii("j:\\acc.log"), + STREAM_WRITE|STREAM_TRUNC|STREAM_SHARE_DENYNONE ); + ByteString aName( String(pThisAcc->GetName()), + RTL_TEXTENCODING_ISO_8859_1 ); + if( aName.Len() ) + { + aStrm << aName.GetBuffer() + << ": "; + } + aStrm << pMsg; + if( pChildAcc ) + { + ByteString aChild( String(pChildAcc->GetName()), + RTL_TEXTENCODING_ISO_8859_1 ); + aStrm << ": " + << aChild.GetBuffer(); + } + aStrm << "\r\n ("; + + if( !bConstrDestr ) + { + ByteString aDesc( String(pThisAcc->getAccessibleDescription()), + RTL_TEXTENCODING_ISO_8859_1 ); + aStrm << aDesc.GetBuffer() + << ", "; + } + + Rectangle aVisArea( pThisAcc->GetVisArea() ); + aStrm << "VA: " + << ByteString::CreateFromInt32( aVisArea.Left() ).GetBuffer() + << "," + << ByteString::CreateFromInt32( aVisArea.Top() ).GetBuffer() + << "," + << ByteString::CreateFromInt32( aVisArea.GetWidth() ).GetBuffer() + << "," + << ByteString::CreateFromInt32( aVisArea.GetHeight() ).GetBuffer(); + + if( pThisAcc->GetFrm() ) + { + Rectangle aBounds( pThisAcc->GetBounds( pThisAcc->GetFrm() ) ); + aStrm << ", BB: " + << ByteString::CreateFromInt32( aBounds.Left() ).GetBuffer() + << "," + << ByteString::CreateFromInt32( aBounds.Top() ).GetBuffer() + << "," + << ByteString::CreateFromInt32( aBounds.GetWidth() ).GetBuffer() + << "," + << ByteString::CreateFromInt32( aBounds.GetHeight() ).GetBuffer() + << ")\r\n"; + } + + aStrm.Flush(); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acccontext.hxx b/sw/source/core/access/acccontext.hxx new file mode 100644 index 000000000000..d9fd0e113d55 --- /dev/null +++ b/sw/source/core/access/acccontext.hxx @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCBASE_HXX +#define _ACCBASE_HXX +#include <accframe.hxx> +#include <accmap.hxx> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase5.hxx> +#include <cppuhelper/interfacecontainer.hxx> + +class Window; +class SwAccessibleMap; +class SwCrsrShell; +class SdrObject; +class SwPaM; +namespace utl { + class AccessibleStateSetHelper; +} +namespace accessibility { + class AccessibleShape; +} +class SwFmtFld; +class SwAccessibleChildContainer; + +const sal_Char sAccessibleServiceName[] = "com.sun.star.accessibility.Accessible"; + +class SwAccessibleContext : + public ::cppu::WeakImplHelper5< + ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleComponent, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::lang::XServiceInfo + >, + public SwAccessibleFrame +{ + // The implements for the XAccessibleSelection interface has been + // 'externalized' and wants access to the protected members like + // GetMap, GetChild, GetParent, and GetFrm. + friend class SwAccessibleSelectionHelper; + + +protected: + + mutable ::osl::Mutex aListenerMutex; + mutable ::osl::Mutex aMutex; + +private: + + ::rtl::OUString sName; // immutable outside constructor + + // The parent if it has been retrieved. This is always an + // SwAccessibleContext. (protected by Mutex) + ::com::sun::star::uno::WeakReference < + ::com::sun::star::accessibility::XAccessible > xWeakParent; + + SwAccessibleMap *pMap; // must be protected by solar mutex + + sal_uInt32 nClientId; // client id in the AccessibleEventNotifier queue + sal_Int16 nRole; // immutable outside constructor + + // The current states (protected by mutex) + sal_Bool bIsShowingState : 1; + sal_Bool bIsEditableState : 1; + sal_Bool bIsOpaqueState : 1; + sal_Bool bIsDefuncState : 1; + + // Are we currently disposing that object (protected by solar mutex)? + sal_Bool bDisposing : 1; + + // #i85634# - boolean, indicating if the accessible context is + // in general registered at the accessible map. + bool bRegisteredAtAccessibleMap; + + void InitStates(); + +protected: + void SetName( const ::rtl::OUString& rName ) { sName = rName; } + inline sal_Int16 GetRole() const + { + return nRole; + } + + void SetParent( SwAccessibleContext *pParent ); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> GetWeakParent() const; + + sal_Bool IsDisposing() const { return bDisposing; } + + Window *GetWindow(); + SwAccessibleMap *GetMap() { return pMap; } + const SwAccessibleMap *GetMap() const { return pMap; } + + /** convenience method to get the SwViewShell through accessibility map */ + inline ViewShell* GetShell() + { + return GetMap()->GetShell(); + } + inline const ViewShell* GetShell() const + { + return GetMap()->GetShell(); + } + + /** convenience method to get SwCrsrShell through accessibility map + * @returns SwCrsrShell, or NULL if none is found */ + SwCrsrShell* GetCrsrShell(); + const SwCrsrShell* GetCrsrShell() const; + + // Notify all children that the vis araea has changed. + // The SwFrm might belong to the current object or to any other child or + // grandchild. + void ChildrenScrolled( const SwFrm *pFrm, const SwRect& rOldVisArea ); + + // The context's showing state changed. May only be called for context that + // exist even if they aren't visible. + void Scrolled( const SwRect& rOldVisArea ); + + // A child has been moved while setting the vis area + void ScrolledWithin( const SwRect& rOldVisArea ); + + // The has been added while setting the vis area + void ScrolledIn(); + + // The context has to be removed while setting the vis area + void ScrolledOut( const SwRect& rOldVisArea ); + + // Invalidate the states of all children of the specified SwFrm. The + // SwFrm might belong the the current object or to any child or grandchild! + // #i27301# - use new type definition for <_nStates> + void InvalidateChildrenStates( const SwFrm* _pFrm, + tAccessibleStates _nStates ); + // <-- + + // Dispose children of the specified SwFrm. The SwFrm might belong to + // the current object or to any other child or grandchild. + void DisposeChildren( const SwFrm *pFrm, + sal_Bool bRecursive ); + + void DisposeShape( const SdrObject *pObj, + ::accessibility::AccessibleShape *pAccImpl ); + void ScrolledInShape( const SdrObject *pObj, + ::accessibility::AccessibleShape *pAccImpl ); + + virtual void _InvalidateContent( sal_Bool bVisibleDataFired ); + + virtual void _InvalidateCursorPos(); + virtual void _InvalidateFocus(); + +public: + + void FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventObject& rEvent ); + +protected: + + // broadcast visual data event + void FireVisibleDataEvent(); + + // broadcast state change event + void FireStateChangedEvent( sal_Int16 nState, sal_Bool bNewState ); + + // Set states for getAccessibleStateSet. + // This base class sets DEFUNC(0/1), EDITABLE(0/1), ENABLED(1), + // SHOWING(0/1), OPAQUE(0/1) and VISIBLE(1). + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + sal_Bool IsEditableState(); + + virtual ::com::sun::star::awt::Rectangle SAL_CALL + getBoundsImpl(sal_Bool bRelative) + throw (::com::sun::star::uno::RuntimeException); + + // #i85634# + inline void NotRegisteredAtAccessibleMap() + { + bRegisteredAtAccessibleMap = false; + } + void RemoveFrmFromAccessibleMap(); + + virtual ~SwAccessibleContext(); + +public: + + SwAccessibleContext( SwAccessibleMap *pMap, sal_Int16 nRole, + const SwFrm *pFrm ); + + //===== XAccessible ===================================================== + + /// Return the XAccessibleContext. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext> SAL_CALL + getAccessibleContext (void) throw (com::sun::star::uno::RuntimeException); + + //===== XAccessibleContext ============================================== + + /// Return the number of currently visible children. + virtual sal_Int32 SAL_CALL getAccessibleChildCount (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the specified child or NULL if index is invalid. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleChild (sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IndexOutOfBoundsException); + + /// Return a reference to the parent. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleParent (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return this objects index among the parents children. + virtual sal_Int32 SAL_CALL + getAccessibleIndexInParent (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return this object's role. + virtual sal_Int16 SAL_CALL + getAccessibleRole (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the object's current name. + virtual ::rtl::OUString SAL_CALL + getAccessibleName (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return NULL to indicate that an empty relation set. + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleRelationSet> SAL_CALL + getAccessibleRelationSet (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the set of current states. + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleStateSet> SAL_CALL + getAccessibleStateSet (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return the parents locale or throw exception if this object has no + parent yet/anymore. + */ + virtual ::com::sun::star::lang::Locale SAL_CALL + getLocale (void) + throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + //===== XAccessibleEventBroadcaster ===================================== + + virtual void SAL_CALL addEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) + throw (::com::sun::star::uno::RuntimeException); + + //===== XAccessibleComponent ============================================ + virtual sal_Bool SAL_CALL containsPoint( + const ::com::sun::star::awt::Point& aPoint ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( + const ::com::sun::star::awt::Point& aPoint ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Point SAL_CALL getLocation() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Size SAL_CALL getSize() + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL grabFocus() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleKeyBinding() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground() + throw (::com::sun::star::uno::RuntimeException); + + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //====== thread safe C++ interface ======================================== + + // The object is not visible an longer and should be destroyed + virtual void Dispose( sal_Bool bRecursive = sal_False ); + + // The child object is not visible an longer and should be destroyed + virtual void DisposeChild( const sw::access::SwAccessibleChild& rFrmOrObj, sal_Bool bRecursive ); + + // The object has been moved by the layout + virtual void InvalidatePosOrSize( const SwRect& rFrm ); + + // The vhild object has been moved by the layout + virtual void InvalidateChildPosOrSize( const sw::access::SwAccessibleChild& rFrmOrObj, + const SwRect& rFrm ); + + // The content may have changed (but it hasn't tohave changed) + void InvalidateContent(); + + // The caretPos has changed + void InvalidateCursorPos(); + + // The Focus state has changed + void InvalidateFocus(); + + // Check states + // #i27301# - use new type definition for <_nStates> + void InvalidateStates( tAccessibleStates _nStates ); + + // the XAccessibleRelationSet may have changed + void InvalidateRelation( sal_uInt16 nType ); + + void InvalidateTextSelection(); // #i27301# - text selection has changed + void InvalidateAttr(); // #i88069# - attributes has changed + + bool HasAdditionalAccessibleChildren(); + + // #i88070# - get additional child by index + Window* GetAdditionalAccessibleChild( const sal_Int32 nIndex ); + + // #i88070# - get all additional accessible children + void GetAdditionalAccessibleChildren( std::vector< Window* >* pChildren ); + + const ::rtl::OUString& GetName() const { return sName; } + + virtual sal_Bool HasCursor(); // required by map to remember that object + + sal_Bool Select( SwPaM *pPaM, SdrObject *pObj, sal_Bool bAdd ); + inline sal_Bool Select( SwPaM& rPaM ) + { + return Select( &rPaM, 0, sal_False ); + } + inline sal_Bool Select( SdrObject *pObj, sal_Bool bAdd ) + { + return Select( 0, pObj, bAdd ); + } + + static ::rtl::OUString GetResource( sal_uInt16 nResId, + const ::rtl::OUString *pArg1 = 0, + const ::rtl::OUString *pArg2 = 0 ); + + +}; + +// some heaviliy used exception support +const sal_Char sDefunc[] = "object is defunctional"; +const sal_Char sMissingWindow[] = "window is missing"; + +#define THROW_RUNTIME_EXCEPTION( ifc, msg ) \ + ::com::sun::star::uno::Reference < ifc > xThis( this ); \ + ::com::sun::star::uno::RuntimeException aExcept( \ + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(msg) ), xThis ); \ + throw aExcept; + +#define CHECK_FOR_DEFUNC_THIS( ifc, ths ) \ + if( !(GetFrm() && GetMap()) ) \ + { \ + ::com::sun::star::uno::Reference < ifc > xThis( ths ); \ + ::com::sun::star::lang::DisposedException aExcept( \ + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sDefunc) ), \ + xThis ); \ + throw aExcept; \ + } + +#define CHECK_FOR_DEFUNC( ifc ) \ + CHECK_FOR_DEFUNC_THIS( ifc, this ) + +#define CHECK_FOR_WINDOW( i, w ) \ + if( !(w) ) \ + { \ + THROW_RUNTIME_EXCEPTION( i, sMissingWindow ); \ + } +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accdoc.cxx b/sw/source/core/access/accdoc.cxx new file mode 100644 index 000000000000..bad6b1b4f5ab --- /dev/null +++ b/sw/source/core/access/accdoc.cxx @@ -0,0 +1,514 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <vcl/window.hxx> +#include <rootfrm.hxx> + + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <tools/link.hxx> +#include <sfx2/viewsh.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <viewsh.hxx> +#include <doc.hxx> +#include <accmap.hxx> +#include <accdoc.hxx> +#include "access.hrc" +#include <pagefrm.hxx> + +const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextDocumentView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleDocumentView"; + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +using lang::IndexOutOfBoundsException; + + + +// +// SwAccessibleDocumentBase: base class for SwAccessibleDocument and +// SwAccessiblePreview +// + +SwAccessibleDocumentBase::SwAccessibleDocumentBase ( SwAccessibleMap *_pMap ) : + SwAccessibleContext( _pMap, AccessibleRole::DOCUMENT, + _pMap->GetShell()->GetLayout() ),//swmod 071107//swmod 071225 + mxParent( _pMap->GetShell()->GetWin()->GetAccessibleParentWindow()->GetAccessible() ), + mpChildWin( 0 ) +{ +} + +SwAccessibleDocumentBase::~SwAccessibleDocumentBase() +{ +} + +void SwAccessibleDocumentBase::SetVisArea() +{ + SolarMutexGuard aGuard; + + SwRect aOldVisArea( GetVisArea() ); + const SwRect& rNewVisArea = GetMap()->GetVisArea(); + if( aOldVisArea != rNewVisArea ) + { + SwAccessibleFrame::SetVisArea( GetMap()->GetVisArea() ); + // #i58139# - showing state of document view needs also be updated. + // Thus, call method <Scrolled(..)> instead of <ChildrenScrolled(..)> +// ChildrenScrolled( GetFrm(), aOldVisArea ); + Scrolled( aOldVisArea ); + } +} + +void SwAccessibleDocumentBase::AddChild( Window *pWin, sal_Bool bFireEvent ) +{ + SolarMutexGuard aGuard; + + OSL_ENSURE( !mpChildWin, "only one child window is supported" ); + if( !mpChildWin ) + { + mpChildWin = pWin; + + if( bFireEvent ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= mpChildWin->GetAccessible(); + FireAccessibleEvent( aEvent ); + } + } +} + +void SwAccessibleDocumentBase::RemoveChild( Window *pWin ) +{ + SolarMutexGuard aGuard; + + OSL_ENSURE( !mpChildWin || pWin == mpChildWin, "invalid child window to remove" ); + if( mpChildWin && pWin == mpChildWin ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.OldValue <<= mpChildWin->GetAccessible(); + FireAccessibleEvent( aEvent ); + + mpChildWin = 0; + } +} + +sal_Int32 SAL_CALL SwAccessibleDocumentBase::getAccessibleChildCount( void ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + // CHECK_FOR_DEFUNC is called by parent + + sal_Int32 nChildren = SwAccessibleContext::getAccessibleChildCount(); + if( !IsDisposing() && mpChildWin ) + nChildren++; + + return nChildren; +} + +uno::Reference< XAccessible> SAL_CALL + SwAccessibleDocumentBase::getAccessibleChild( sal_Int32 nIndex ) + throw (uno::RuntimeException, + lang::IndexOutOfBoundsException) +{ + SolarMutexGuard aGuard; + + if( mpChildWin ) + { + CHECK_FOR_DEFUNC( XAccessibleContext ) + if ( nIndex == GetChildCount( *(GetMap()) ) ) + { + return mpChildWin->GetAccessible(); + } + } + + return SwAccessibleContext::getAccessibleChild( nIndex ); +} + + +uno::Reference< XAccessible> SAL_CALL SwAccessibleDocumentBase::getAccessibleParent (void) + throw (uno::RuntimeException) +{ + return mxParent; +} + +sal_Int32 SAL_CALL SwAccessibleDocumentBase::getAccessibleIndexInParent (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + uno::Reference < XAccessibleContext > xAcc( mxParent->getAccessibleContext() ); + uno::Reference < XAccessible > xThis( this ); + sal_Int32 nCount = xAcc->getAccessibleChildCount(); + + for( sal_Int32 i=0; i < nCount; i++ ) + { + if( xAcc->getAccessibleChild( i ) == xThis ) + return i; + } + return -1L; +} + +OUString SAL_CALL SwAccessibleDocumentBase::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + return GetResource( STR_ACCESS_DOC_DESC ); +} + +awt::Rectangle SAL_CALL SwAccessibleDocumentBase::getBounds() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + Window *pWin = GetWindow(); + + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Rectangle aPixBounds( pWin->GetWindowExtentsRelative( pWin->GetAccessibleParentWindow() ) ); + awt::Rectangle aBox( aPixBounds.Left(), aPixBounds.Top(), + aPixBounds.GetWidth(), aPixBounds.GetHeight() ); + + return aBox; +} + + +awt::Point SAL_CALL SwAccessibleDocumentBase::getLocation() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + Window *pWin = GetWindow(); + + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Point aPixPos( pWin->GetWindowExtentsRelative( pWin->GetAccessibleParentWindow() ).TopLeft() ); + awt::Point aLoc( aPixPos.X(), aPixPos.Y() ); + + return aLoc; +} + + +::com::sun::star::awt::Point SAL_CALL SwAccessibleDocumentBase::getLocationOnScreen() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + Window *pWin = GetWindow(); + + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Point aPixPos( pWin->GetWindowExtentsRelative( 0 ).TopLeft() ); + awt::Point aLoc( aPixPos.X(), aPixPos.Y() ); + + return aLoc; +} + + +::com::sun::star::awt::Size SAL_CALL SwAccessibleDocumentBase::getSize() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + Window *pWin = GetWindow(); + + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Size aPixSize( pWin->GetWindowExtentsRelative( 0 ).GetSize() ); + awt::Size aSize( aPixSize.Width(), aPixSize.Height() ); + + return aSize; +} + +sal_Bool SAL_CALL SwAccessibleDocumentBase::containsPoint( + const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + Window *pWin = GetWindow(); + + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Rectangle aPixBounds( pWin->GetWindowExtentsRelative( 0 ) ); + aPixBounds.Move(-aPixBounds.Left(), -aPixBounds.Top()); + + Point aPixPoint( aPoint.X, aPoint.Y ); + return aPixBounds.IsInside( aPixPoint ); +} + +uno::Reference< XAccessible > SAL_CALL SwAccessibleDocumentBase::getAccessibleAtPoint( + const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + if( mpChildWin ) + { + CHECK_FOR_DEFUNC( XAccessibleComponent ) + + Window *pWin = GetWindow(); + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ) + + Point aPixPoint( aPoint.X, aPoint.Y ); // px rel to window + if( mpChildWin->GetWindowExtentsRelative( pWin ).IsInside( aPixPoint ) ) + return mpChildWin->GetAccessible(); + } + + return SwAccessibleContext::getAccessibleAtPoint( aPoint ); +} + +// +// SwAccessibeDocument +// + +void SwAccessibleDocument::GetStates( + ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SwAccessibleContext::GetStates( rStateSet ); + + // MULTISELECTABLE + rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE ); +} + + +SwAccessibleDocument::SwAccessibleDocument ( SwAccessibleMap* pInitMap ) : + SwAccessibleDocumentBase( pInitMap ), + maSelectionHelper( *this ) +{ + SetName( GetResource( STR_ACCESS_DOC_NAME ) ); + Window *pWin = pInitMap->GetShell()->GetWin(); + if( pWin ) + { + pWin->AddChildEventListener( LINK( this, SwAccessibleDocument, WindowChildEventListener )); + sal_uInt16 nCount = pWin->GetChildCount(); + for( sal_uInt16 i=0; i < nCount; i++ ) + { + Window* pChildWin = pWin->GetChild( i ); + if( pChildWin && + AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + AddChild( pChildWin, sal_False ); + } + } +} + +SwAccessibleDocument::~SwAccessibleDocument() +{ + Window *pWin = GetMap() ? GetMap()->GetShell()->GetWin() : 0; + if( pWin ) + pWin->RemoveChildEventListener( LINK( this, SwAccessibleDocument, WindowChildEventListener )); +} + +void SwAccessibleDocument::Dispose( sal_Bool bRecursive ) +{ + OSL_ENSURE( GetFrm() && GetMap(), "already disposed" ); + + Window *pWin = GetMap() ? GetMap()->GetShell()->GetWin() : 0; + if( pWin ) + pWin->RemoveChildEventListener( LINK( this, SwAccessibleDocument, WindowChildEventListener )); + SwAccessibleContext::Dispose( bRecursive ); +} + +IMPL_LINK( SwAccessibleDocument, WindowChildEventListener, VclSimpleEvent*, pEvent ) +{ + DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" ); + if ( pEvent && pEvent->ISA( VclWindowEvent ) ) + { + VclWindowEvent *pVclEvent = static_cast< VclWindowEvent * >( pEvent ); + DBG_ASSERT( pVclEvent->GetWindow(), "Window???" ); + switch ( pVclEvent->GetId() ) + { + case VCLEVENT_WINDOW_SHOW: // send create on show for direct accessible children + { + Window* pChildWin = static_cast< Window* >( pVclEvent->GetData() ); + if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + { + AddChild( pChildWin ); + } + } + break; + case VCLEVENT_WINDOW_HIDE: // send destroy on hide for direct accessible children + { + Window* pChildWin = static_cast< Window* >( pVclEvent->GetData() ); + if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + { + RemoveChild( pChildWin ); + } + } + break; + case VCLEVENT_OBJECT_DYING: // send destroy on hide for direct accessible children + { + Window* pChildWin = pVclEvent->GetWindow(); + if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + { + RemoveChild( pChildWin ); + } + } + break; + } + } + return 0; +} + + +OUString SAL_CALL SwAccessibleDocument::getImplementationName() + throw( uno::RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleDocument::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +uno::Sequence< OUString > SAL_CALL SwAccessibleDocument::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +//===== XInterface ====================================================== + +uno::Any SwAccessibleDocument::queryInterface( + const uno::Type& rType ) + throw ( uno::RuntimeException ) +{ + uno::Any aRet; + if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ) ) + { + uno::Reference<XAccessibleSelection> aSelect = this; + aRet <<= aSelect; + } + else + aRet = SwAccessibleContext::queryInterface( rType ); + return aRet; +} + +//====== XTypeProvider ==================================================== +uno::Sequence< uno::Type > SAL_CALL SwAccessibleDocument::getTypes() + throw(uno::RuntimeException) +{ + uno::Sequence< uno::Type > aTypes( SwAccessibleDocumentBase::getTypes() ); + + sal_Int32 nIndex = aTypes.getLength(); + aTypes.realloc( nIndex + 1 ); + + uno::Type* pTypes = aTypes.getArray(); + pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ); + + return aTypes; +} + +uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleDocument::getImplementationId() + throw(uno::RuntimeException) +{ + SolarMutexGuard aGuard; + static uno::Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +//===== XAccessibleSelection ============================================ + +void SwAccessibleDocument::selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + maSelectionHelper.selectAccessibleChild(nChildIndex); +} + +sal_Bool SwAccessibleDocument::isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + return maSelectionHelper.isAccessibleChildSelected(nChildIndex); +} + +void SwAccessibleDocument::clearAccessibleSelection( ) + throw ( uno::RuntimeException ) +{ + maSelectionHelper.clearAccessibleSelection(); +} + +void SwAccessibleDocument::selectAllAccessibleChildren( ) + throw ( uno::RuntimeException ) +{ + maSelectionHelper.selectAllAccessibleChildren(); +} + +sal_Int32 SwAccessibleDocument::getSelectedAccessibleChildCount( ) + throw ( uno::RuntimeException ) +{ + return maSelectionHelper.getSelectedAccessibleChildCount(); +} + +uno::Reference<XAccessible> SwAccessibleDocument::getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + return maSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex); +} + +// index has to be treated as global child index. +void SwAccessibleDocument::deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + maSelectionHelper.deselectAccessibleChild( nChildIndex ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accdoc.hxx b/sw/source/core/access/accdoc.hxx new file mode 100644 index 000000000000..2a4e125b7fb4 --- /dev/null +++ b/sw/source/core/access/accdoc.hxx @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCDOC_HXX +#define _ACCDOC_HXX +#include "acccontext.hxx" +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <accselectionhelper.hxx> + +class VclSimpleEvent; + +/** + * base class for SwAccessibleDocument (in this same header file) and + * SwAccessiblePreview + */ +class SwAccessibleDocumentBase : public SwAccessibleContext +{ + ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible> mxParent; + + Window* mpChildWin; // protected by solar mutext + + using SwAccessibleFrame::SetVisArea; + +protected: + + virtual ~SwAccessibleDocumentBase(); + +public: + + SwAccessibleDocumentBase( SwAccessibleMap* pInitMap ); + + void SetVisArea(); + + virtual void AddChild( Window *pWin, sal_Bool bFireEvent = sal_True ); + virtual void RemoveChild( Window *pWin ); + + //===== XAccessibleContext ============================================== + + /// Return the number of currently visible children. + virtual sal_Int32 SAL_CALL getAccessibleChildCount (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the specified child or NULL if index is invalid. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleChild (sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IndexOutOfBoundsException); + + /// Return a reference to the parent. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleParent (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return this objects index among the parents children. + virtual sal_Int32 SAL_CALL + getAccessibleIndexInParent (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) throw (com::sun::star::uno::RuntimeException); + + //===== XAccessibleComponent ============================================== + virtual sal_Bool SAL_CALL containsPoint( + const ::com::sun::star::awt::Point& aPoint ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( + const ::com::sun::star::awt::Point& aPoint ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Point SAL_CALL getLocation() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::awt::Size SAL_CALL getSize() + throw (::com::sun::star::uno::RuntimeException); +}; + + + +/** + * access to an accessible Writer document + */ +class SwAccessibleDocument : public SwAccessibleDocumentBase, + public com::sun::star::accessibility::XAccessibleSelection +{ + // Implementation for XAccessibleSelection interface + SwAccessibleSelectionHelper maSelectionHelper; + +protected: + + // Set states for getAccessibleStateSet. + // This drived class additinaly sets MULTISELECTABLE(1) + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + virtual ~SwAccessibleDocument(); + +public: + + SwAccessibleDocument( SwAccessibleMap* pInitMap ); + + DECL_LINK( WindowChildEventListener, VclSimpleEvent* ); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XInterface ====================================================== + + // XInterface is inherited through SwAcessibleContext and + // XAccessibleSelection. These methods are needed to avoid + // ambigiouties. + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire( ) throw () + { SwAccessibleContext::acquire(); }; + + virtual void SAL_CALL release( ) throw () + { SwAccessibleContext::release(); }; + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + //===== XAccessibleSelection ============================================ + + virtual void SAL_CALL selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL clearAccessibleSelection( ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL selectAllAccessibleChildren( ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + // index has to be treated as global child index. + virtual void SAL_CALL deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + //====== thread safe C++ interface ======================================== + + // The object is not visible an longer and should be destroyed + virtual void Dispose( sal_Bool bRecursive = sal_False ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accembedded.cxx b/sw/source/core/access/accembedded.cxx new file mode 100644 index 000000000000..5ccbc03f3339 --- /dev/null +++ b/sw/source/core/access/accembedded.cxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <rtl/uuid.h> +#include <flyfrm.hxx> +#include "accembedded.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextEmbeddedObject"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleEmbeddedObject"; + +SwAccessibleEmbeddedObject::SwAccessibleEmbeddedObject( + SwAccessibleMap* pInitMap, + const SwFlyFrm* pFlyFrm ) : + SwAccessibleNoTextFrame( pInitMap, AccessibleRole::EMBEDDED_OBJECT, pFlyFrm ) +{ +} + +SwAccessibleEmbeddedObject::~SwAccessibleEmbeddedObject() +{ +} + +OUString SAL_CALL SwAccessibleEmbeddedObject::getImplementationName() + throw( uno::RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleEmbeddedObject::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +uno::Sequence< OUString > SAL_CALL SwAccessibleEmbeddedObject::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + + +uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleEmbeddedObject::getImplementationId() + throw(uno::RuntimeException) +{ + SolarMutexGuard aGuard; + static uno::Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accembedded.hxx b/sw/source/core/access/accembedded.hxx new file mode 100644 index 000000000000..94f8e2d43c20 --- /dev/null +++ b/sw/source/core/access/accembedded.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCEMBEDDED_HXX +#define _ACCEMBEDDED_HXX +#include "accnotextframe.hxx" + +class SwAccessibleEmbeddedObject : public SwAccessibleNoTextFrame +{ + +protected: + + virtual ~SwAccessibleEmbeddedObject(); + +public: + + SwAccessibleEmbeddedObject( SwAccessibleMap* pInitMap, + const SwFlyFrm* pFlyFrm ); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfootnote.cxx b/sw/source/core/access/accfootnote.cxx new file mode 100644 index 000000000000..2efd6cf6d78f --- /dev/null +++ b/sw/source/core/access/accfootnote.cxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <osl/mutex.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <rtl/uuid.h> +#include <vcl/svapp.hxx> +#include <ftnfrm.hxx> +#include <fmtftn.hxx> +#include <txtftn.hxx> +#include <viewsh.hxx> +#include <accmap.hxx> +#include "accfootnote.hxx" +#include "access.hrc" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +const sal_Char sServiceNameFootnote[] = "com.sun.star.text.AccessibleFootnoteView"; +const sal_Char sServiceNameEndnote[] = "com.sun.star.text.AccessibleEndnoteView"; +const sal_Char sImplementationNameFootnote[] = "com.sun.star.comp.Writer.SwAccessibleFootnoteView"; +const sal_Char sImplementationNameEndnote[] = "com.sun.star.comp.Writer.SwAccessibleEndnoteView"; + +SwAccessibleFootnote::SwAccessibleFootnote( + SwAccessibleMap* pInitMap, + sal_Bool bIsEndnote, + sal_Int32 nFootEndNote, + const SwFtnFrm *pFtnFrm ) : + SwAccessibleContext( pInitMap, + bIsEndnote ? AccessibleRole::END_NOTE : AccessibleRole::FOOTNOTE, + pFtnFrm ) +{ + SolarMutexGuard aGuard; + + sal_uInt16 nResId = bIsEndnote ? STR_ACCESS_ENDNOTE_NAME + : STR_ACCESS_FOOTNOTE_NAME; + OUString sArg( OUString::valueOf( nFootEndNote ) ); + SetName( GetResource( nResId, &sArg ) ); +} + +SwAccessibleFootnote::~SwAccessibleFootnote() +{ +} + +OUString SAL_CALL SwAccessibleFootnote::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + sal_uInt16 nResId = AccessibleRole::END_NOTE == GetRole() + ? STR_ACCESS_ENDNOTE_DESC + : STR_ACCESS_FOOTNOTE_DESC ; + + OUString sArg; + const SwTxtFtn *pTxtFtn = + static_cast< const SwFtnFrm *>( GetFrm() )->GetAttr(); + if( pTxtFtn ) + { + const SwDoc *pDoc = GetMap()->GetShell()->GetDoc(); + sArg = pTxtFtn->GetFtn().GetViewNumStr( *pDoc ); + } + + return GetResource( nResId, &sArg ); +} + +OUString SAL_CALL SwAccessibleFootnote::getImplementationName() + throw( RuntimeException ) +{ + if( AccessibleRole::END_NOTE == GetRole() ) + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationNameEndnote)); + else + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationNameFootnote)); +} + +sal_Bool SAL_CALL SwAccessibleFootnote::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + if( sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ) ) + return sal_True; + else if( AccessibleRole::END_NOTE == GetRole() ) + return sTestServiceName.equalsAsciiL( sServiceNameEndnote, sizeof(sServiceNameEndnote)-1 ); + else + return sTestServiceName.equalsAsciiL( sServiceNameFootnote, sizeof(sServiceNameFootnote)-1 ); + +} + +Sequence< OUString > SAL_CALL SwAccessibleFootnote::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + if( AccessibleRole::END_NOTE == GetRole() ) + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceNameEndnote) ); + else + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceNameFootnote) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +Sequence< sal_Int8 > SAL_CALL SwAccessibleFootnote::getImplementationId() + throw(RuntimeException) +{ + SolarMutexGuard aGuard; + static Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +sal_Bool SwAccessibleFootnote::IsEndnote( const SwFtnFrm *pFtnFrm ) +{ + const SwTxtFtn *pTxtFtn = pFtnFrm ->GetAttr(); + return pTxtFtn && pTxtFtn->GetFtn().IsEndNote() ; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfootnote.hxx b/sw/source/core/access/accfootnote.hxx new file mode 100644 index 000000000000..521247685a16 --- /dev/null +++ b/sw/source/core/access/accfootnote.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCFOOTNOTE_HXX +#define _ACCFOOTNOTE_HXX + +#include <sal/types.h> + +#include <acccontext.hxx> + +class SwAccessibleMap; +class SwFtnFrm; + +class SwAccessibleFootnote : public SwAccessibleContext +{ + +protected: + + virtual ~SwAccessibleFootnote(); + +public: + + SwAccessibleFootnote( SwAccessibleMap* pInitMap, + sal_Bool bIsEndnote, + sal_Int32 nFootEndNote, + const SwFtnFrm *pFtnFrm ); + + + //===== XAccessibleContext ============================================== + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + static sal_Bool IsEndnote( const SwFtnFrm *pFrm ); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accframe.cxx b/sw/source/core/access/accframe.cxx new file mode 100644 index 000000000000..c19c7cf8ef1d --- /dev/null +++ b/sw/source/core/access/accframe.cxx @@ -0,0 +1,496 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include <hintids.hxx> +#include <editeng/brshitem.hxx> +#include <flyfrm.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> +#include <sectfrm.hxx> +#include <section.hxx> +#include <viewsh.hxx> +#include <viewopt.hxx> +#include <doc.hxx> +#include <frmatr.hxx> +#include <pagefrm.hxx> +#include <pagedesc.hxx> +#include <fmtanchr.hxx> +#include <fldbas.hxx> +#include <dcontact.hxx> +#include <accmap.hxx> +#include <accfrmobjslist.hxx> +#include <accfrmobjmap.hxx> +#include <accframe.hxx> + +using namespace sw::access; + +// Regarding visibilily (or in terms of accessibility: regarding the showing +// state): A frame is visible and therfor contained in the tree if its frame +// size overlaps with the visible area. The bounding box however is the +// frame's paint area. +/* static */ sal_Int32 SwAccessibleFrame::GetChildCount( SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm *pFrm, + sal_Bool bInPagePreview ) +{ + sal_Int32 nCount = 0; + + const SwAccessibleChildSList aVisList( rVisArea, *pFrm, rAccMap ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + if( rLower.IsAccessible( bInPagePreview ) ) + { + nCount++; + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + nCount += GetChildCount( rAccMap, + rVisArea, rLower.GetSwFrm(), + bInPagePreview ); + } + ++aIter; + } + + return nCount; +} + +/* static */ SwAccessibleChild SwAccessibleFrame::GetChild( + SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm& rFrm, + sal_Int32& rPos, + sal_Bool bInPagePreview ) +{ + SwAccessibleChild aRet; + + if( rPos >= 0 ) + { + if( SwAccessibleChildMap::IsSortingRequired( rFrm ) ) + { + // We need a sorted list here + const SwAccessibleChildMap aVisMap( rVisArea, rFrm, rAccMap ); + SwAccessibleChildMap::const_iterator aIter( aVisMap.begin() ); + while( aIter != aVisMap.end() && !aRet.IsValid() ) + { + const SwAccessibleChild& rLower = (*aIter).second; + if( rLower.IsAccessible( bInPagePreview ) ) + { + if( 0 == rPos ) + aRet = rLower; + else + rPos--; + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + aRet = GetChild( rAccMap, + rVisArea, *(rLower.GetSwFrm()), rPos, + bInPagePreview ); + } + ++aIter; + } + } + else + { + // The unsorted list is sorted enough, because it return lower + // frames in the correct order. + const SwAccessibleChildSList aVisList( rVisArea, rFrm, rAccMap ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() && !aRet.IsValid() ) + { + const SwAccessibleChild& rLower = *aIter; + if( rLower.IsAccessible( bInPagePreview ) ) + { + if( 0 == rPos ) + aRet = rLower; + else + rPos--; + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + aRet = GetChild( rAccMap, + rVisArea, *(rLower.GetSwFrm()), rPos, + bInPagePreview ); + } + ++aIter; + } + } + } + + return aRet; +} + +/* static */ sal_Bool SwAccessibleFrame::GetChildIndex( + SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm& rFrm, + const SwAccessibleChild& rChild, + sal_Int32& rPos, + sal_Bool bInPagePreview ) +{ + sal_Bool bFound = sal_False; + + if( SwAccessibleChildMap::IsSortingRequired( rFrm ) ) + { + // We need a sorted list here + const SwAccessibleChildMap aVisMap( rVisArea, rFrm, rAccMap ); + SwAccessibleChildMap::const_iterator aIter( aVisMap.begin() ); + while( aIter != aVisMap.end() && !bFound ) + { + const SwAccessibleChild& rLower = (*aIter).second; + if( rLower.IsAccessible( bInPagePreview ) ) + { + if( rChild == rLower ) + bFound = sal_True; + else + rPos++; + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + bFound = GetChildIndex( rAccMap, + rVisArea, *(rLower.GetSwFrm()), rChild, + rPos, bInPagePreview ); + } + ++aIter; + } + } + else + { + // The unsorted list is sorted enough, because it return lower + // frames in the correct order. + const SwAccessibleChildSList aVisList( rVisArea, rFrm, rAccMap ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() && !bFound ) + { + const SwAccessibleChild& rLower = *aIter; + if( rLower.IsAccessible( bInPagePreview ) ) + { + if( rChild == rLower ) + bFound = sal_True; + else + rPos++; + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + bFound = GetChildIndex( rAccMap, + rVisArea, *(rLower.GetSwFrm()), rChild, + rPos, bInPagePreview ); + } + ++aIter; + } + } + + return bFound; +} + +SwAccessibleChild SwAccessibleFrame::GetChildAtPixel( const SwRect& rVisArea, + const SwFrm& rFrm, + const Point& rPixPos, + sal_Bool bInPagePreview, + SwAccessibleMap& rAccMap ) +{ + SwAccessibleChild aRet; + + if( SwAccessibleChildMap::IsSortingRequired( rFrm ) ) + { + // We need a sorted list here, and we have to reverse iterate, + // because objects in front should be returned. + const SwAccessibleChildMap aVisMap( rVisArea, rFrm, rAccMap ); + SwAccessibleChildMap::const_reverse_iterator aRIter( aVisMap.rbegin() ); + while( aRIter != aVisMap.rend() && !aRet.IsValid() ) + { + const SwAccessibleChild& rLower = (*aRIter).second; + // A frame is returned if it's frame size is inside the visarea + // and the positiion is inside the frame's paint area. + if( rLower.IsAccessible( bInPagePreview ) ) + { + SwRect aLogBounds( rLower.GetBounds( rAccMap ) ); + if( !aLogBounds.IsEmpty() ) + { + Rectangle aPixBounds( rAccMap.CoreToPixel( aLogBounds.SVRect() ) ); + if( aPixBounds.IsInside( rPixPos ) ) + aRet = rLower; + } + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + aRet = GetChildAtPixel( rVisArea, *(rLower.GetSwFrm()), rPixPos, + bInPagePreview, rAccMap ); + } + ++aRIter; + } + } + else + { + // The unsorted list is sorted enough, because it returns lower + // frames in the correct order. Morover, we can iterate forward, + // because the lowers don't overlap! + const SwAccessibleChildSList aVisList( rVisArea, rFrm, rAccMap ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() && !aRet.IsValid() ) + { + const SwAccessibleChild& rLower = *aIter; + // A frame is returned if it's frame size is inside the visarea + // and the positiion is inside the frame's paint area. + if( rLower.IsAccessible( bInPagePreview ) ) + { + SwRect aLogBounds( rLower.GetBounds( rAccMap ) ); + if( !aLogBounds.IsEmpty() ) + { + Rectangle aPixBounds( rAccMap.CoreToPixel( aLogBounds.SVRect() ) ); + if( aPixBounds.IsInside( rPixPos ) ) + aRet = rLower; + } + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + aRet = GetChildAtPixel( rVisArea, *(rLower.GetSwFrm()), rPixPos, + bInPagePreview, rAccMap ); + } + ++aIter; + } + } + + return aRet; +} + +/* static */ void SwAccessibleFrame::GetChildren( SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm& rFrm, + ::std::list< SwAccessibleChild >& rChildren, + sal_Bool bInPagePreview ) +{ + if( SwAccessibleChildMap::IsSortingRequired( rFrm ) ) + { + // We need a sorted list here + const SwAccessibleChildMap aVisMap( rVisArea, rFrm, rAccMap ); + SwAccessibleChildMap::const_iterator aIter( aVisMap.begin() ); + while( aIter != aVisMap.end() ) + { + const SwAccessibleChild& rLower = (*aIter).second; + if( rLower.IsAccessible( bInPagePreview ) ) + { + rChildren.push_back( rLower ); + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + GetChildren( rAccMap, rVisArea, *(rLower.GetSwFrm()), + rChildren, bInPagePreview ); + } + ++aIter; + } + } + else + { + // The unsorted list is sorted enough, because it return lower + // frames in the correct order. + const SwAccessibleChildSList aVisList( rVisArea, rFrm, rAccMap ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + if( rLower.IsAccessible( bInPagePreview ) ) + { + rChildren.push_back( rLower ); + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + GetChildren( rAccMap, rVisArea, *(rLower.GetSwFrm()), + rChildren, bInPagePreview ); + } + ++aIter; + } + } +} + +SwRect SwAccessibleFrame::GetBounds( const SwAccessibleMap& rAccMap, + const SwFrm *pFrm ) +{ + if( !pFrm ) + pFrm = GetFrm(); + + SwAccessibleChild aFrm( pFrm ); + SwRect aBounds( aFrm.GetBounds( rAccMap ).Intersection( maVisArea ) ); + return aBounds; +} + +sal_Bool SwAccessibleFrame::IsEditable( ViewShell *pVSh ) const +{ + const SwFrm *pFrm = GetFrm(); + if( !pFrm ) + return sal_False; + + OSL_ENSURE( pVSh, "no view shell" ); + if( pVSh && (pVSh->GetViewOptions()->IsReadonly() || + pVSh->IsPreView()) ) + return sal_False; + + if( !pFrm->IsRootFrm() && pFrm->IsProtected() ) + return sal_False; + + return sal_True; +} + +sal_Bool SwAccessibleFrame::IsOpaque( ViewShell *pVSh ) const +{ + SwAccessibleChild aFrm( GetFrm() ); + if( !aFrm.GetSwFrm() ) + return sal_False; + + OSL_ENSURE( pVSh, "no view shell" ); + if( !pVSh ) + return sal_False; + + const SwViewOption *pVOpt = pVSh->GetViewOptions(); + do + { + const SwFrm *pFrm = aFrm.GetSwFrm(); + if( pFrm->IsRootFrm() ) + return sal_True; + + if( pFrm->IsPageFrm() && !pVOpt->IsPageBack() ) + return sal_False; + + const SvxBrushItem &rBack = pFrm->GetAttrSet()->GetBackground(); + if( !rBack.GetColor().GetTransparency() || + rBack.GetGraphicPos() != GPOS_NONE ) + return sal_True; + + // If a fly frame has a transparent background color, we have to consider the background. + // But a background color "no fill"/"auto fill" has *not* to be considered. + if( pFrm->IsFlyFrm() && + (rBack.GetColor().GetTransparency() != 0) && + (rBack.GetColor() != COL_TRANSPARENT) + ) + return sal_True; + + if( pFrm->IsSctFrm() ) + { + const SwSection* pSection = ((SwSectionFrm*)pFrm)->GetSection(); + if( pSection && ( TOX_HEADER_SECTION == pSection->GetType() || + TOX_CONTENT_SECTION == pSection->GetType() ) && + !pVOpt->IsReadonly() && + SwViewOption::IsIndexShadings() ) + return sal_True; + } + if( pFrm->IsFlyFrm() ) + aFrm = static_cast<const SwFlyFrm*>(pFrm)->GetAnchorFrm(); + else + aFrm = pFrm->GetUpper(); + } while( aFrm.GetSwFrm() && !aFrm.IsAccessible( IsInPagePreview() ) ); + + return sal_False; +} + +SwAccessibleFrame::SwAccessibleFrame( const SwRect& rVisArea, + const SwFrm *pF, + sal_Bool bIsPagePreview ) : + maVisArea( rVisArea ), + mpFrm( pF ), + mbIsInPagePreview( bIsPagePreview ) +{ +} + +SwAccessibleFrame::~SwAccessibleFrame() +{ +} + +/* static */ const SwFrm* SwAccessibleFrame::GetParent( const SwAccessibleChild& rFrmOrObj, + sal_Bool bInPagePreview ) +{ + return rFrmOrObj.GetParent( bInPagePreview ); +} + +String SwAccessibleFrame::GetFormattedPageNumber() const +{ + sal_uInt16 nPageNum = GetFrm()->GetVirtPageNum(); + sal_uInt32 nFmt = GetFrm()->FindPageFrm()->GetPageDesc() + ->GetNumType().GetNumberingType(); + if( SVX_NUM_NUMBER_NONE == nFmt ) + nFmt = SVX_NUM_ARABIC; + + String sRet( FormatNumber( nPageNum, nFmt ) ); + return sRet; +} + +sal_Int32 SwAccessibleFrame::GetChildCount( SwAccessibleMap& rAccMap ) const +{ + return GetChildCount( rAccMap, maVisArea, mpFrm, IsInPagePreview() ); +} + +sw::access::SwAccessibleChild SwAccessibleFrame::GetChild( + SwAccessibleMap& rAccMap, + sal_Int32 nPos ) const +{ + return SwAccessibleFrame::GetChild( rAccMap, maVisArea, *mpFrm, nPos, IsInPagePreview() ); +} + +sal_Int32 SwAccessibleFrame::GetChildIndex( SwAccessibleMap& rAccMap, + const sw::access::SwAccessibleChild& rChild ) const +{ + sal_Int32 nPos = 0; + return GetChildIndex( rAccMap, maVisArea, *mpFrm, rChild, nPos, IsInPagePreview() ) + ? nPos + : -1L; +} + +sw::access::SwAccessibleChild SwAccessibleFrame::GetChildAtPixel( + const Point& rPos, + SwAccessibleMap& rAccMap ) const +{ + return GetChildAtPixel( maVisArea, *mpFrm, rPos, IsInPagePreview(), rAccMap ); +} + +void SwAccessibleFrame::GetChildren( SwAccessibleMap& rAccMap, + ::std::list< sw::access::SwAccessibleChild >& rChildren ) const +{ + GetChildren( rAccMap, maVisArea, *mpFrm, rChildren, IsInPagePreview() ); +} + +sal_Bool SwAccessibleFrame::IsShowing( const SwAccessibleMap& rAccMap, + const sw::access::SwAccessibleChild& rFrmOrObj ) const +{ + return IsShowing( rFrmOrObj.GetBox( rAccMap ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accframe.hxx b/sw/source/core/access/accframe.hxx new file mode 100644 index 000000000000..7aa7e42f9e0c --- /dev/null +++ b/sw/source/core/access/accframe.hxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCFRAME_HXX +#define _ACCFRAME_HXX + +#include <swrect.hxx> + +#include <sal/types.h> +#include <tools/string.hxx> + +#include <list> +#include <accfrmobj.hxx> + +class SwAccessibleMap; +class SwFrm; +class ViewShell; +namespace sw { namespace access { + class SwAccessibleChild; +}} + +// Any method of this class must be called with an acquired solar mutex! + +class SwAccessibleFrame +{ + SwRect maVisArea; + const SwFrm* mpFrm; + const sal_Bool mbIsInPagePreview; + +protected: + // #i77106# - method needs to be called by new class <SwAccessibleTableColHeaders> + static sal_Int32 GetChildCount( SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm *pFrm, + sal_Bool bInPagePreview ); +private: + static sw::access::SwAccessibleChild GetChild( SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm& rFrm, + sal_Int32& rPos, + sal_Bool bInPagePreview); + + static sal_Bool GetChildIndex( SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm& rFrm, + const sw::access::SwAccessibleChild& rChild, + sal_Int32& rPos, + sal_Bool bInPagePreview ); + + static sw::access::SwAccessibleChild GetChildAtPixel( const SwRect& rVisArea, + const SwFrm& rFrm, + const Point& rPos, + sal_Bool bInPagePreview, + SwAccessibleMap& rAccMap ); + + static void GetChildren( SwAccessibleMap& rAccMap, + const SwRect& rVisArea, + const SwFrm& rFrm, + ::std::list< sw::access::SwAccessibleChild >& rChildren, + sal_Bool bInPagePreview ); + +protected: + + sal_Bool IsEditable( ViewShell *pVSh ) const; + + sal_Bool IsOpaque( ViewShell *pVSh ) const; + + sal_Bool IsShowing( const SwAccessibleMap& rAccMap, + const sw::access::SwAccessibleChild& rFrmOrObj ) const; + inline sal_Bool IsShowing( const SwRect& rFrm ) const; + inline sal_Bool IsShowing( const SwAccessibleMap& rAccMap ) const; + + inline sal_Bool IsInPagePreview() const + { + return mbIsInPagePreview; + } + + inline void ClearFrm() + { + mpFrm = 0; + } + + SwAccessibleFrame( const SwRect& rVisArea, + const SwFrm *pFrm, + sal_Bool bIsPagePreview ); + virtual ~SwAccessibleFrame(); + +public: + // Return the SwFrm this context is attached to. + const SwFrm* GetFrm() const { return mpFrm; }; + + static const SwFrm* GetParent( const sw::access::SwAccessibleChild& rFrmOrObj, + sal_Bool bInPagePreview ); + + sal_Int32 GetChildIndex( SwAccessibleMap& rAccMap, + const sw::access::SwAccessibleChild& rChild ) const; + +protected: + + // Return the bounding box of the frame clipped to the vis area. If + // no frame is specified, use this' frame. + SwRect GetBounds( const SwAccessibleMap& rAccMap, + const SwFrm *pFrm = 0 ); + + // Return the upper that has a context attached. This might be + // another one than the immediate upper. + inline const SwFrm *GetParent() const; + + // Return the lower count or the nth lower, there the lowers have a + // not be same one as the SwFrm's lowers + sal_Int32 GetChildCount( SwAccessibleMap& rAccMap ) const; + sw::access::SwAccessibleChild GetChild( SwAccessibleMap& rAccMap, + sal_Int32 nPos ) const; + sw::access::SwAccessibleChild GetChildAtPixel( const Point& rPos, + SwAccessibleMap& rAccMap ) const; + void GetChildren( SwAccessibleMap& rAccMap, + ::std::list< sw::access::SwAccessibleChild >& rChildren ) const; + + inline void SetVisArea( const SwRect& rNewVisArea ) + { + maVisArea = rNewVisArea; + } + + inline const SwRect& GetVisArea() const + { + return maVisArea; + } + + + String GetFormattedPageNumber() const; +}; + +inline sal_Bool SwAccessibleFrame::IsShowing( const SwRect& rFrm ) const +{ + return rFrm.IsOver( maVisArea ); +} + +inline sal_Bool SwAccessibleFrame::IsShowing( const SwAccessibleMap& rAccMap ) const +{ + sw::access::SwAccessibleChild aFrmOrObj( GetFrm() ); + return IsShowing( rAccMap, aFrmOrObj ); +} + +inline const SwFrm *SwAccessibleFrame::GetParent() const +{ + sw::access::SwAccessibleChild aFrmOrObj( GetFrm() ); + return GetParent( aFrmOrObj, IsInPagePreview() ); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accframebase.cxx b/sw/source/core/access/accframebase.cxx new file mode 100644 index 000000000000..f96b050260b6 --- /dev/null +++ b/sw/source/core/access/accframebase.cxx @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <frmfmt.hxx> +#include <ndnotxt.hxx> +#include <flyfrm.hxx> +#include <cntfrm.hxx> +#include <fmtcntnt.hxx> +#include <ndindex.hxx> +#include "fesh.hxx" +#include <hints.hxx> +#include "accmap.hxx" +#include "accframebase.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +sal_Bool SwAccessibleFrameBase::IsSelected() +{ + sal_Bool bRet = sal_False; + + DBG_ASSERT( GetMap(), "no map?" ); + const ViewShell *pVSh = GetMap()->GetShell(); + DBG_ASSERT( pVSh, "no shell?" ); + if( pVSh->ISA( SwFEShell ) ) + { + const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh ); + const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm(); + if( pFlyFrm == GetFrm() ) + bRet = sal_True; + } + + return bRet; +} + +void SwAccessibleFrameBase::GetStates( + ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SwAccessibleContext::GetStates( rStateSet ); + + const ViewShell *pVSh = GetMap()->GetShell(); + DBG_ASSERT( pVSh, "no shell?" ); + sal_Bool bSelectable = pVSh->ISA( SwFEShell ); + + // SELECTABLE + if( bSelectable ) + rStateSet.AddState( AccessibleStateType::SELECTABLE ); + + // FOCUSABLE + if( bSelectable ) + rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + + // SELECTED and FOCUSED + if( IsSelected() ) + { + rStateSet.AddState( AccessibleStateType::SELECTED ); + OSL_ENSURE( bIsSelected, "bSelected out of sync" ); + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() ) + rStateSet.AddState( AccessibleStateType::FOCUSED ); + } +} + + +sal_uInt8 SwAccessibleFrameBase::GetNodeType( const SwFlyFrm *pFlyFrm ) +{ + sal_uInt8 nType = ND_TEXTNODE; + if( pFlyFrm->Lower() ) + { + if( pFlyFrm->Lower()->IsNoTxtFrm() ) + { + const SwCntntFrm *pCntFrm = + static_cast<const SwCntntFrm *>( pFlyFrm->Lower() ); + nType = pCntFrm->GetNode()->GetNodeType(); + } + } + else + { + const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + const SwNodeIndex *pNdIdx = rCntnt.GetCntntIdx(); + if( pNdIdx ) + { + const SwCntntNode *pCNd = + (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetCntntNode(); + if( pCNd ) + nType = pCNd->GetNodeType(); + } + } + + return nType; +} + +SwAccessibleFrameBase::SwAccessibleFrameBase( + SwAccessibleMap* pInitMap, + sal_Int16 nInitRole, + const SwFlyFrm* pFlyFrm ) : + SwAccessibleContext( pInitMap, nInitRole, pFlyFrm ), + bIsSelected( sal_False ) +{ + SolarMutexGuard aGuard; + + const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); + const_cast< SwFrmFmt * >( pFrmFmt )->Add( this ); + + SetName( pFrmFmt->GetName() ); + + bIsSelected = IsSelected(); +} + +void SwAccessibleFrameBase::_InvalidateCursorPos() +{ + sal_Bool bNewSelected = IsSelected(); + sal_Bool bOldSelected; + + { + osl::MutexGuard aGuard( aMutex ); + bOldSelected = bIsSelected; + bIsSelected = bNewSelected; + } + + if( bNewSelected ) + { + // remember that object as the one that has the caret. This is + // neccessary to notify that object if the cursor leaves it. + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } + + if( bOldSelected != bNewSelected ) + { + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() && bNewSelected ) + FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); + FireStateChangedEvent( AccessibleStateType::SELECTED, bNewSelected ); + if( pWin && pWin->HasFocus() && !bNewSelected ) + FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); + + uno::Reference< XAccessible > xParent( GetWeakParent() ); + if( xParent.is() ) + { + SwAccessibleContext *pAcc = + static_cast <SwAccessibleContext *>( xParent.get() ); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; + pAcc->FireAccessibleEvent( aEvent ); + } + } +} + +void SwAccessibleFrameBase::_InvalidateFocus() +{ + Window *pWin = GetWindow(); + if( pWin ) + { + sal_Bool bSelected; + + { + osl::MutexGuard aGuard( aMutex ); + bSelected = bIsSelected; + } + OSL_ENSURE( bSelected, "focus object should be selected" ); + + FireStateChangedEvent( AccessibleStateType::FOCUSED, + pWin->HasFocus() && bSelected ); + } +} + +sal_Bool SwAccessibleFrameBase::HasCursor() +{ + osl::MutexGuard aGuard( aMutex ); + return bIsSelected; +} + + +SwAccessibleFrameBase::~SwAccessibleFrameBase() +{ +} + +void SwAccessibleFrameBase::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) +{ + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; + const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() ); + switch( nWhich ) + { + case RES_NAME_CHANGED: + if( pFlyFrm ) + { + const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt(); + OSL_ENSURE( pFrmFmt == GetRegisteredIn(), "invalid frame" ); + + OUString sOldName( GetName() ); + OSL_ENSURE( !pOld || + static_cast < const SwStringMsgPoolItem * >( pOld )->GetString() == String( sOldName ), + "invalid old name" ); + + const String& rNewName = pFrmFmt->GetName(); + SetName( rNewName ); + OSL_ENSURE( !pNew || + static_cast < const SwStringMsgPoolItem * >( pNew )->GetString() == rNewName, + "invalid new name" ); + + if( sOldName != GetName() ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::NAME_CHANGED; + aEvent.OldValue <<= sOldName; + aEvent.NewValue <<= GetName(); + FireAccessibleEvent( aEvent ); + } + } + break; + case RES_OBJECTDYING: + // mba: it seems that this class intentionally does not call code in base class SwClient + if( GetRegisteredIn() == + static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) ) + GetRegisteredInNonConst()->Remove( this ); + break; + + case RES_FMT_CHG: + if( static_cast< const SwFmtChg * >(pNew)->pChangedFmt == GetRegisteredIn() && + static_cast< const SwFmtChg * >(pOld)->pChangedFmt->IsFmtInDTOR() ) + GetRegisteredInNonConst()->Remove( this ); + break; + + default: + // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING + break; + } +} + +void SwAccessibleFrameBase::Dispose( sal_Bool bRecursive ) +{ + SolarMutexGuard aGuard; + + if( GetRegisteredIn() ) + GetRegisteredInNonConst()->Remove( this ); + + SwAccessibleContext::Dispose( bRecursive ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accframebase.hxx b/sw/source/core/access/accframebase.hxx new file mode 100644 index 000000000000..8ac7f2e2e0c6 --- /dev/null +++ b/sw/source/core/access/accframebase.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCFRAMEBASE_HXX +#define _ACCFRAMEBASE_HXX + +#include <acccontext.hxx> + +#include <calbck.hxx> + +class SwFlyFrm; + +class SwAccessibleFrameBase : public SwAccessibleContext, + public SwClient +{ + sal_Bool bIsSelected; // protected by base class mutex + + sal_Bool IsSelected(); + +protected: + + // Set states for getAccessibleStateSet. + // This drived class additionaly sets SELECTABLE(1), SELECTED(+), + // FOCUSABLE(1) and FOCUSED(+) + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + virtual void _InvalidateCursorPos(); + virtual void _InvalidateFocus(); + + virtual ~SwAccessibleFrameBase(); + virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); + +public: + + SwAccessibleFrameBase( SwAccessibleMap* pInitMap, + sal_Int16 nInitRole, + const SwFlyFrm *pFlyFrm ); + + virtual sal_Bool HasCursor(); // required by map to remember that object + + static sal_uInt8 GetNodeType( const SwFlyFrm *pFlyFrm ); + + // The object is not visible an longer and should be destroyed + virtual void Dispose( sal_Bool bRecursive = sal_False ); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfrmobj.cxx b/sw/source/core/access/accfrmobj.cxx new file mode 100644 index 000000000000..6b3f73c713b3 --- /dev/null +++ b/sw/source/core/access/accfrmobj.cxx @@ -0,0 +1,430 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <accfrmobj.hxx> + +#include <accmap.hxx> +#include <acccontext.hxx> + +#include <viewsh.hxx> +#include <rootfrm.hxx> +#include <flyfrm.hxx> +#include <pagefrm.hxx> +#include <cellfrm.hxx> +#include <swtable.hxx> +#include <dflyobj.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <dcontact.hxx> + +#include <vcl/window.hxx> + +namespace css = ::com::sun::star; + +namespace sw { namespace access { + +SwAccessibleChild::SwAccessibleChild() + : mpFrm( 0 ) + , mpDrawObj( 0 ) + , mpWindow( 0 ) +{} + +SwAccessibleChild::SwAccessibleChild( const SdrObject* pDrawObj ) + : mpFrm( 0 ) + , mpDrawObj( 0 ) + , mpWindow( 0 ) +{ + Init( pDrawObj ); +} + +SwAccessibleChild::SwAccessibleChild( const SwFrm* pFrm ) + : mpFrm( 0 ) + , mpDrawObj( 0 ) + , mpWindow( 0 ) +{ + Init( pFrm ); +} + +SwAccessibleChild::SwAccessibleChild( Window* pWindow ) + : mpFrm( 0 ) + , mpDrawObj( 0 ) + , mpWindow( 0 ) +{ + Init( pWindow ); +} + + +SwAccessibleChild::SwAccessibleChild( const SwFrm* pFrm, + const SdrObject* pDrawObj, + Window* pWindow ) +{ + if ( pFrm ) + { + Init( pFrm ); + } + else if ( pDrawObj ) + { + Init( pDrawObj ); + } + else if ( pWindow ) + { + Init( pWindow ); + } + OSL_ENSURE( (!pFrm || pFrm == mpFrm) && + (!pDrawObj || pDrawObj == mpDrawObj) && + (!pWindow || pWindow == mpWindow), + "invalid frame/object/window combination" ); + +} + +void SwAccessibleChild::Init( const SdrObject* pDrawObj ) +{ + mpDrawObj = pDrawObj; + mpFrm = mpDrawObj && mpDrawObj->ISA(SwVirtFlyDrawObj) + ? static_cast < const SwVirtFlyDrawObj * >( mpDrawObj )->GetFlyFrm() + : 0; + mpWindow = 0; +} + +void SwAccessibleChild::Init( const SwFrm* pFrm ) +{ + mpFrm = pFrm; + mpDrawObj = mpFrm && mpFrm->IsFlyFrm() + ? static_cast < const SwFlyFrm * >( mpFrm )->GetVirtDrawObj() + : 0; + mpWindow = 0; +} + +void SwAccessibleChild::Init( Window* pWindow ) +{ + mpWindow = pWindow; + mpFrm = 0; + mpDrawObj = 0; +} + +bool SwAccessibleChild::IsAccessible( sal_Bool bPagePreview ) const +{ + bool bRet( false ); + + if ( mpFrm ) + { + bRet = mpFrm->IsAccessibleFrm() && + ( !mpFrm->IsCellFrm() || + static_cast<const SwCellFrm *>( mpFrm )->GetTabBox()->GetSttNd() != 0 ) && + !mpFrm->IsInCoveredCell() && + ( bPagePreview || + !mpFrm->IsPageFrm() ); + } + else if ( mpDrawObj ) + { + bRet = true; + } + else if ( mpWindow ) + { + bRet = true; + } + + return bRet; +} + +bool SwAccessibleChild::IsBoundAsChar() const +{ + bool bRet( false ); + + if ( mpFrm ) + { + bRet = mpFrm->IsFlyFrm() && + static_cast< const SwFlyFrm *>(mpFrm)->IsFlyInCntFrm(); + } + else if ( mpDrawObj ) + { + const SwFrmFmt* mpFrmFmt = ::FindFrmFmt( mpDrawObj ); + bRet = mpFrmFmt + ? (FLY_AS_CHAR == mpFrmFmt->GetAnchor().GetAnchorId()) + : false; + } + else if ( mpWindow ) + { + bRet = false; + } + + return bRet; +} + +SwAccessibleChild::SwAccessibleChild( const SwAccessibleChild& r ) + : mpFrm( r.mpFrm ) + , mpDrawObj( r.mpDrawObj ) + , mpWindow( r.mpWindow ) +{} + +SwAccessibleChild& SwAccessibleChild::operator=( const SwAccessibleChild& r ) +{ + mpDrawObj = r.mpDrawObj; + mpFrm = r.mpFrm; + mpWindow = r.mpWindow; + + return *this; +} + +SwAccessibleChild& SwAccessibleChild::operator=( const SdrObject* pDrawObj ) +{ + Init( pDrawObj ); + return *this; +} + +SwAccessibleChild& SwAccessibleChild::operator=( const SwFrm* pFrm ) +{ + Init( pFrm ); + return *this; +} + +SwAccessibleChild& SwAccessibleChild::operator=( Window* pWindow ) +{ + Init( pWindow ); + return *this; +} + +bool SwAccessibleChild::operator==( const SwAccessibleChild& r ) const +{ + return mpFrm == r.mpFrm && + mpDrawObj == r.mpDrawObj && + mpWindow == r.mpWindow; +} + +bool SwAccessibleChild::IsValid() const +{ + return mpFrm != 0 || + mpDrawObj != 0 || + mpWindow != 0; +} + +const SdrObject* SwAccessibleChild::GetDrawObject() const +{ + return mpDrawObj; +} + +const SwFrm *SwAccessibleChild::GetSwFrm() const +{ + return mpFrm; +} + +Window* SwAccessibleChild::GetWindow() const +{ + return mpWindow; +} + +bool SwAccessibleChild::IsVisibleChildrenOnly() const +{ + bool bRet( false ); + + if ( !mpFrm ) + { + bRet = true; + } + else + { + bRet = mpFrm->IsRootFrm() || + !( mpFrm->IsTabFrm() || + mpFrm->IsInTab() || + ( IsBoundAsChar() && + static_cast<const SwFlyFrm*>(mpFrm)->GetAnchorFrm()->IsInTab() ) ); + } + + return bRet; +} + +SwRect SwAccessibleChild::GetBox( const SwAccessibleMap& rAccMap ) const +{ + SwRect aBox; + + if ( mpFrm ) + { + if ( mpFrm->IsPageFrm() && + static_cast< const SwPageFrm * >( mpFrm )->IsEmptyPage() ) + { + aBox = SwRect( mpFrm->Frm().Left(), mpFrm->Frm().Top()-1, 1, 1 ); + } + else if ( mpFrm->IsTabFrm() ) + { + aBox = SwRect( mpFrm->Frm() ); + aBox.Intersection( mpFrm->GetUpper()->Frm() ); + } + else + { + aBox = mpFrm->Frm(); + } + } + else if( mpDrawObj ) + { + aBox = SwRect( mpDrawObj->GetCurrentBoundRect() ); + } + else if ( mpWindow ) + { + aBox = SwRect( rAccMap.GetShell()->GetWin()->PixelToLogic( + Rectangle( mpWindow->GetPosPixel(), + mpWindow->GetSizePixel() ) ) ); +} + + return aBox; +} + +SwRect SwAccessibleChild::GetBounds( const SwAccessibleMap& rAccMap ) const +{ + SwRect aBound; + + if( mpFrm ) + { + if( mpFrm->IsPageFrm() && + static_cast< const SwPageFrm * >( mpFrm )->IsEmptyPage() ) + { + aBound = SwRect( mpFrm->Frm().Left(), mpFrm->Frm().Top()-1, 0, 0 ); + } + else + aBound = mpFrm->PaintArea(); + } + else if( mpDrawObj ) + { + aBound = GetBox( rAccMap ); + } + else if ( mpWindow ) + { + aBound = GetBox( rAccMap ); + } + + return aBound; +} + +bool SwAccessibleChild::AlwaysIncludeAsChild() const +{ + bool bAlwaysIncludedAsChild( false ); + + if ( mpWindow ) + { + bAlwaysIncludedAsChild = true; + } + + return bAlwaysIncludedAsChild; +} + +const SwFrm* SwAccessibleChild::GetParent( const sal_Bool bInPagePreview ) const +{ + const SwFrm* pParent( 0 ); + + if ( mpFrm ) + { + if( mpFrm->IsFlyFrm() ) + { + const SwFlyFrm* pFly = static_cast< const SwFlyFrm *>( mpFrm ); + if( pFly->IsFlyInCntFrm() ) + { + // For FLY_AS_CHAR the parent is the anchor + pParent = pFly->GetAnchorFrm(); + OSL_ENSURE( SwAccessibleChild( pParent ).IsAccessible( bInPagePreview ), + "parent is not accessible" ); + } + else + { + // In any other case the parent is the root frm + // (in page preview, the page frame) + if( bInPagePreview ) + pParent = pFly->FindPageFrm(); + else + pParent = pFly->getRootFrm(); + } + } + else + { + SwAccessibleChild aUpper( mpFrm->GetUpper() ); + while( aUpper.GetSwFrm() && !aUpper.IsAccessible(bInPagePreview) ) + { + aUpper = aUpper.GetSwFrm()->GetUpper(); + } + pParent = aUpper.GetSwFrm(); + } + } + else if( mpDrawObj ) + { + const SwDrawContact *pContact = + static_cast< const SwDrawContact* >( GetUserCall( mpDrawObj ) ); + OSL_ENSURE( pContact, "sdr contact is missing" ); + if( pContact ) + { + const SwFrmFmt *pFrmFmt = pContact->GetFmt(); + OSL_ENSURE( pFrmFmt, "frame format is missing" ); + if( pFrmFmt && FLY_AS_CHAR == pFrmFmt->GetAnchor().GetAnchorId() ) + { + // For FLY_AS_CHAR the parent is the anchor + pParent = pContact->GetAnchorFrm(); + OSL_ENSURE( SwAccessibleChild( pParent ).IsAccessible( bInPagePreview ), + "parent is not accessible" ); + + } + else + { + // In any other case the parent is the root frm + if( bInPagePreview ) + pParent = pContact->GetAnchorFrm()->FindPageFrm(); + else + pParent = pContact->GetAnchorFrm()->getRootFrm(); + } + } + } + else if ( mpWindow ) + { + css::uno::Reference < css::accessibility::XAccessible > xAcc = + mpWindow->GetAccessible(); + if ( xAcc.is() ) + { + css::uno::Reference < css::accessibility::XAccessibleContext > xAccContext = + xAcc->getAccessibleContext(); + if ( xAccContext.is() ) + { + css::uno::Reference < css::accessibility::XAccessible > xAccParent = + xAccContext->getAccessibleParent(); + if ( xAccParent.is() ) + { + SwAccessibleContext* pAccParentImpl = + dynamic_cast< SwAccessibleContext *>( xAccParent.get() ); + if ( pAccParentImpl ) + { + pParent = pAccParentImpl->GetFrm(); + } + } + } + } + } + + return pParent; +} + +} } // eof of namespace sw::access + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfrmobj.hxx b/sw/source/core/access/accfrmobj.hxx new file mode 100644 index 000000000000..8b196711277e --- /dev/null +++ b/sw/source/core/access/accfrmobj.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCFRMOBJ_HXX +#define _ACCFRMOBJ_HXX + +#include <sal/types.h> + +class SwAccessibleMap; +class SwFrm; +class SdrObject; +class Window; +class SwRect; + +namespace sw { namespace access { + +class SwAccessibleChild +{ + public: + SwAccessibleChild(); + explicit SwAccessibleChild( const SdrObject* pDrawObj ); + explicit SwAccessibleChild( const SwFrm* pFrm ); + explicit SwAccessibleChild( Window* pWindow ); + SwAccessibleChild( const SwFrm* pFrm, + const SdrObject* pDrawObj, + Window* pWindow ); + + SwAccessibleChild( const SwAccessibleChild& r ); + SwAccessibleChild& operator=( const SwAccessibleChild& r ); + + SwAccessibleChild& operator=( const SdrObject* pDrawObj ); + SwAccessibleChild& operator=( const SwFrm* pFrm ); + SwAccessibleChild& operator=( Window* pWindow ); + + bool operator==( const SwAccessibleChild& r ) const; + + bool IsValid() const; + + const SwFrm* GetSwFrm() const; + const SdrObject* GetDrawObject() const; + Window* GetWindow() const; + + const SwFrm* GetParent( const sal_Bool bInPagePreview ) const; + + bool IsAccessible( sal_Bool bPagePreview ) const; + bool IsBoundAsChar() const; + + bool IsVisibleChildrenOnly() const; + SwRect GetBox( const SwAccessibleMap& rAccMap ) const; + SwRect GetBounds( const SwAccessibleMap& rAccMap ) const; + + /** indicating, if accessible child is included even, if the corresponding + object is not visible. */ + bool AlwaysIncludeAsChild() const; + + private: + const SwFrm* mpFrm; + const SdrObject* mpDrawObj; + Window* mpWindow; + + void Init( const SdrObject* pDrawObj ); + void Init( const SwFrm* pFrm ); + void Init( Window* pWindow ); +}; + + +} } // eof of namespace sw::access + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfrmobjmap.cxx b/sw/source/core/access/accfrmobjmap.cxx new file mode 100644 index 000000000000..e7fd8644da77 --- /dev/null +++ b/sw/source/core/access/accfrmobjmap.cxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <accfrmobjmap.hxx> +#include <accframe.hxx> +#include <accmap.hxx> +#include <acccontext.hxx> + +#include <viewsh.hxx> +#include <doc.hxx> +#include <frmfmt.hxx> +#include <pagefrm.hxx> +#include <txtfrm.hxx> +#include <node.hxx> +#include <sortedobjs.hxx> +#include <anchoredobject.hxx> + +#include <svx/svdobj.hxx> + +using namespace sw::access; + +SwAccessibleChildMap::SwAccessibleChildMap( const SwRect& rVisArea, + const SwFrm& rFrm, + SwAccessibleMap& rAccMap ) + : nHellId( rAccMap.GetShell()->GetDoc()->GetHellId() ) + , nControlsId( rAccMap.GetShell()->GetDoc()->GetControlsId() ) +{ + const bool bVisibleChildrenOnly = SwAccessibleChild( &rFrm ).IsVisibleChildrenOnly(); + + sal_uInt32 nPos = 0; + SwAccessibleChild aLower( rFrm.GetLower() ); + while( aLower.GetSwFrm() ) + { + if ( !bVisibleChildrenOnly || + aLower.AlwaysIncludeAsChild() || + aLower.GetBox( rAccMap ).IsOver( rVisArea ) ) + { + insert( nPos++, SwAccessibleChildMapKey::TEXT, aLower ); + } + + aLower = aLower.GetSwFrm()->GetNext(); + } + + if ( rFrm.IsPageFrm() ) + { + OSL_ENSURE( bVisibleChildrenOnly, "page frame within tab frame???" ); + const SwPageFrm *pPgFrm = + static_cast< const SwPageFrm * >( &rFrm ); + const SwSortedObjs *pObjs = pPgFrm->GetSortedObjs(); + if ( pObjs ) + { + for( sal_uInt16 i=0; i<pObjs->Count(); i++ ) + { + aLower = (*pObjs)[i]->GetDrawObj(); + if ( aLower.GetBox( rAccMap ).IsOver( rVisArea ) ) + { + insert( aLower.GetDrawObject(), aLower ); + } + } + } + } + else if( rFrm.IsTxtFrm() ) + { + const SwSortedObjs *pObjs = rFrm.GetDrawObjs(); + if ( pObjs ) + { + for( sal_uInt16 i=0; i<pObjs->Count(); i++ ) + { + aLower = (*pObjs)[i]->GetDrawObj(); + if ( aLower.IsBoundAsChar() && + ( !bVisibleChildrenOnly || + aLower.AlwaysIncludeAsChild() || + aLower.GetBox( rAccMap ).IsOver( rVisArea ) ) ) + { + insert( aLower.GetDrawObject(), aLower ); + } + } + } + + { + ::rtl::Reference < SwAccessibleContext > xAccImpl = + rAccMap.GetContextImpl( &rFrm, sal_False ); + if( xAccImpl.is() ) + { + SwAccessibleContext* pAccImpl = xAccImpl.get(); + if ( pAccImpl && + pAccImpl->HasAdditionalAccessibleChildren() ) + { + std::vector< Window* >* pAdditionalChildren = + new std::vector< Window* >(); + pAccImpl->GetAdditionalAccessibleChildren( pAdditionalChildren ); + + sal_Int32 nCounter( 0 ); + for ( std::vector< Window* >::iterator aIter = pAdditionalChildren->begin(); + aIter != pAdditionalChildren->end(); + ++aIter ) + { + aLower = (*aIter); + insert( ++nCounter, SwAccessibleChildMapKey::XWINDOW, aLower ); + } + + delete pAdditionalChildren; + } + } + } + } +} + +::std::pair< SwAccessibleChildMap::iterator, bool > SwAccessibleChildMap::insert( + const sal_uInt32 nPos, + const SwAccessibleChildMapKey::LayerId eLayerId, + const SwAccessibleChild& rLower ) +{ + SwAccessibleChildMapKey aKey( eLayerId, nPos ); + value_type aEntry( aKey, rLower ); + return _SwAccessibleChildMap::insert( aEntry ); +} + +::std::pair< SwAccessibleChildMap::iterator, bool > SwAccessibleChildMap::insert( + const SdrObject *pObj, + const SwAccessibleChild& rLower ) +{ + const SdrLayerID nLayer = pObj->GetLayer(); + SwAccessibleChildMapKey::LayerId eLayerId = + (nHellId == nLayer) + ? SwAccessibleChildMapKey::HELL + : ( (nControlsId == nLayer) + ? SwAccessibleChildMapKey::CONTROLS + : SwAccessibleChildMapKey::HEAVEN ); + SwAccessibleChildMapKey aKey( eLayerId, pObj->GetOrdNum() ); + value_type aEntry( aKey, rLower ); + return _SwAccessibleChildMap::insert( aEntry ); +} + +/* static */ sal_Bool SwAccessibleChildMap::IsSortingRequired( const SwFrm& rFrm ) +{ + return ( rFrm.IsPageFrm() && + static_cast< const SwPageFrm& >( rFrm ).GetSortedObjs() ) || + ( rFrm.IsTxtFrm() && + rFrm.GetDrawObjs() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfrmobjmap.hxx b/sw/source/core/access/accfrmobjmap.hxx new file mode 100644 index 000000000000..441202e6acb9 --- /dev/null +++ b/sw/source/core/access/accfrmobjmap.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCFRMOBJMAP_HXX +#define _ACCFRMOBJMAP_HXX + +#include <accfrmobj.hxx> + +#include <svx/svdtypes.hxx> + +#include <map> + +class SwAccessibleMap; +class SwDoc; +class SwRect; +class SwFrm; +class SdrObject; + +class SwAccessibleChildMapKey +{ +public: + enum LayerId { INVALID, HELL, TEXT, HEAVEN, CONTROLS, XWINDOW }; + + inline SwAccessibleChildMapKey() + : eLayerId( INVALID ) + , nOrdNum( 0 ) + {} + + inline SwAccessibleChildMapKey( LayerId eId, sal_uInt32 nOrd ) + : eLayerId( eId ) + , nOrdNum( nOrd ) + {} + + inline bool operator()( const SwAccessibleChildMapKey& r1, + const SwAccessibleChildMapKey& r2 ) const + { + return (r1.eLayerId == r2.eLayerId) + ? (r1.nOrdNum < r2.nOrdNum) + : (r1.eLayerId < r2.eLayerId); + } + +private: + + LayerId eLayerId; + sal_uInt32 nOrdNum; + +}; + +typedef ::std::map < SwAccessibleChildMapKey, sw::access::SwAccessibleChild, SwAccessibleChildMapKey > + _SwAccessibleChildMap; + +class SwAccessibleChildMap : public _SwAccessibleChildMap +{ + const SdrLayerID nHellId; + const SdrLayerID nControlsId; + + ::std::pair< iterator, bool > insert( const sal_uInt32 nPos, + const SwAccessibleChildMapKey::LayerId eLayerId, + const sw::access::SwAccessibleChild& rLower ); + ::std::pair< iterator, bool > insert( const SdrObject* pObj, + const sw::access::SwAccessibleChild& rLower ); + +public: + + SwAccessibleChildMap( const SwRect& rVisArea, + const SwFrm& rFrm, + SwAccessibleMap& rAccMap ); + + static sal_Bool IsSortingRequired( const SwFrm& rFrm ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfrmobjslist.cxx b/sw/source/core/access/accfrmobjslist.cxx new file mode 100644 index 000000000000..846e06a0435c --- /dev/null +++ b/sw/source/core/access/accfrmobjslist.cxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <accfrmobjslist.hxx> +#include <accmap.hxx> +#include <acccontext.hxx> + +#include <pagefrm.hxx> +#include <sortedobjs.hxx> +#include <anchoredobject.hxx> + +using namespace ::sw::access; + +SwAccessibleChildSList_const_iterator::SwAccessibleChildSList_const_iterator( + const SwAccessibleChildSList& rLst, + SwAccessibleMap& rAccMap ) + : rList( rLst ), + aCurr( rList.GetFrm().GetLower() ), + nNextObj( 0 ) +{ + if( !aCurr.GetSwFrm() ) + { + const SwFrm& rFrm = rList.GetFrm(); + if( rFrm.IsPageFrm() ) + { + const SwPageFrm& rPgFrm = static_cast< const SwPageFrm& >( rFrm ); + const SwSortedObjs *pObjs = rPgFrm.GetSortedObjs(); + if( pObjs && pObjs->Count() ) + { + aCurr = (*pObjs)[nNextObj++]->GetDrawObj(); + } + } + else if( rFrm.IsTxtFrm() ) + { + const SwSortedObjs *pObjs = rFrm.GetDrawObjs(); + if ( pObjs && pObjs->Count() ) + { + aCurr = (*pObjs)[nNextObj++]->GetDrawObj(); + while( aCurr.IsValid() && !aCurr.IsBoundAsChar() ) + { + aCurr = (nNextObj < pObjs->Count()) + ? (*pObjs)[nNextObj++]->GetDrawObj() + : static_cast< const SdrObject *>( 0 ); + } + } + if ( !aCurr.IsValid() ) + { + ::rtl::Reference < SwAccessibleContext > xAccImpl = + rAccMap.GetContextImpl( &rFrm, sal_False ); + if( xAccImpl.is() ) + { + SwAccessibleContext* pAccImpl = xAccImpl.get(); + aCurr = SwAccessibleChild( pAccImpl->GetAdditionalAccessibleChild( 0 ) ); + ++nNextObj; + } + } + } + } + + if( rList.IsVisibleChildrenOnly() ) + { + // Find the first visible + while( aCurr.IsValid() && + !aCurr.AlwaysIncludeAsChild() && + !aCurr.GetBox( rAccMap ).IsOver( rList.GetVisArea() ) ) + { + next(); + } + } +} + +SwAccessibleChildSList_const_iterator& SwAccessibleChildSList_const_iterator::next() +{ + bool bNextTaken( true ); + if( aCurr.GetDrawObject() || aCurr.GetWindow() ) + { + bNextTaken = false; + } + else if( aCurr.GetSwFrm() ) + { + aCurr = aCurr.GetSwFrm()->GetNext(); + if( !aCurr.GetSwFrm() ) + { + bNextTaken = false; + } + } + + if( !bNextTaken ) + { + const SwFrm& rFrm = rList.GetFrm(); + if( rFrm.IsPageFrm() ) + { + const SwPageFrm& rPgFrm = static_cast< const SwPageFrm& >( rFrm ); + const SwSortedObjs *pObjs = rPgFrm.GetSortedObjs(); + aCurr = ( pObjs && nNextObj < pObjs->Count() ) + ? (*pObjs)[nNextObj++]->GetDrawObj() + : static_cast< const SdrObject *>( 0 ); + } + else if( rFrm.IsTxtFrm() ) + { + const SwSortedObjs* pObjs = rFrm.GetDrawObjs(); + const sal_uInt32 nObjsCount = pObjs ? pObjs->Count() : 0; + aCurr = ( pObjs && nNextObj < nObjsCount ) + ? (*pObjs)[nNextObj++]->GetDrawObj() + : static_cast< const SdrObject *>( 0 ); + while( aCurr.IsValid() && !aCurr.IsBoundAsChar() ) + { + aCurr = ( nNextObj < nObjsCount ) + ? (*pObjs)[nNextObj++]->GetDrawObj() + : static_cast< const SdrObject *>( 0 ); + } + if ( !aCurr.IsValid() ) + { + ::rtl::Reference < SwAccessibleContext > xAccImpl = + rList.GetAccMap().GetContextImpl( &rFrm, sal_False ); + if( xAccImpl.is() ) + { + SwAccessibleContext* pAccImpl = xAccImpl.get(); + aCurr = SwAccessibleChild( pAccImpl->GetAdditionalAccessibleChild( nNextObj - nObjsCount ) ); + ++nNextObj; + } + } + } + } + + return *this; +} + +SwAccessibleChildSList_const_iterator& SwAccessibleChildSList_const_iterator::next_visible() +{ + next(); + while( aCurr.IsValid() && + !aCurr.AlwaysIncludeAsChild() && + !aCurr.GetBox( rList.GetAccMap() ).IsOver( rList.GetVisArea() ) ) + { + next(); + } + + return *this; +} + +SwAccessibleChildSList_const_iterator& SwAccessibleChildSList_const_iterator::operator++() +{ + return rList.IsVisibleChildrenOnly() ? next_visible() : next(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accfrmobjslist.hxx b/sw/source/core/access/accfrmobjslist.hxx new file mode 100644 index 000000000000..78052177fbac --- /dev/null +++ b/sw/source/core/access/accfrmobjslist.hxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCFRMOBJSLIST_HXX +#define _ACCFRMOBJSLIST_HXX + +#include <accfrmobj.hxx> +#include <swrect.hxx> + +class SwAccessibleMap; + +class SwAccessibleChildSList; + +class SwAccessibleChildSList_const_iterator +{ +private: + friend class SwAccessibleChildSList; + + const SwAccessibleChildSList& rList; // The frame we are iterating over + sw::access::SwAccessibleChild aCurr; // The current object + sal_uInt16 nNextObj; // The index of the current sdr object + + inline SwAccessibleChildSList_const_iterator( const SwAccessibleChildSList& rLst ) + : rList( rLst ) + , nNextObj( 0 ) + {} + + SwAccessibleChildSList_const_iterator( const SwAccessibleChildSList& rLst, + SwAccessibleMap& rAccMap ); + + SwAccessibleChildSList_const_iterator& next(); + SwAccessibleChildSList_const_iterator& next_visible(); + +public: + + inline SwAccessibleChildSList_const_iterator( const SwAccessibleChildSList_const_iterator& rIter ) + : rList( rIter.rList ) + , aCurr( rIter.aCurr ) + , nNextObj( rIter.nNextObj ) + {} + + inline sal_Bool operator==( const SwAccessibleChildSList_const_iterator& r ) const + { + return aCurr == r.aCurr; + } + + inline sal_Bool operator!=( + const SwAccessibleChildSList_const_iterator& r ) const + { + return !(*this == r); + } + + SwAccessibleChildSList_const_iterator& operator++(); + + inline const sw::access::SwAccessibleChild& operator*() const + { + return aCurr; + } +}; + +// An iterator to iterate over a frame's child in any order +class SwAccessibleChildSList +{ + const SwRect maVisArea; + const SwFrm& mrFrm; + const sal_Bool mbVisibleChildrenOnly; + SwAccessibleMap& mrAccMap; + +public: + + typedef SwAccessibleChildSList_const_iterator const_iterator; + + inline SwAccessibleChildSList( const SwFrm& rFrm, + SwAccessibleMap& rAccMap ) + : maVisArea() + , mrFrm( rFrm ) + , mbVisibleChildrenOnly( sal_False ) + , mrAccMap( rAccMap ) + {} + + inline SwAccessibleChildSList( const SwRect& rVisArea, + const SwFrm& rFrm, + SwAccessibleMap& rAccMap ) + : maVisArea( rVisArea ) + , mrFrm( rFrm ) + , mbVisibleChildrenOnly( sw::access::SwAccessibleChild( &rFrm ).IsVisibleChildrenOnly() ) + , mrAccMap( rAccMap ) + { + } + + inline const_iterator begin() const + { + return SwAccessibleChildSList_const_iterator( *this, mrAccMap ); + } + + inline const_iterator end() const + { + return SwAccessibleChildSList_const_iterator( *this ); + } + + inline const SwFrm& GetFrm() const + { + return mrFrm; + } + + inline sal_Bool IsVisibleChildrenOnly() const + { + return mbVisibleChildrenOnly; + } + + inline const SwRect& GetVisArea() const + { + return maVisArea; + } + + inline SwAccessibleMap& GetAccMap() const + { + return mrAccMap; + } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accgraphic.cxx b/sw/source/core/access/accgraphic.cxx new file mode 100644 index 000000000000..4c389e2f85c1 --- /dev/null +++ b/sw/source/core/access/accgraphic.cxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <rtl/uuid.h> +#include <flyfrm.hxx> +#include "accgraphic.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextGraphicObject"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleGraphic"; + +SwAccessibleGraphic::SwAccessibleGraphic( + SwAccessibleMap* pInitMap, + const SwFlyFrm* pFlyFrm ) : + SwAccessibleNoTextFrame( pInitMap, AccessibleRole::GRAPHIC, pFlyFrm ) +{ +} + +SwAccessibleGraphic::~SwAccessibleGraphic() +{ +} + +OUString SAL_CALL SwAccessibleGraphic::getImplementationName() + throw( RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleGraphic::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +Sequence< OUString > SAL_CALL SwAccessibleGraphic::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +Sequence< sal_Int8 > SAL_CALL SwAccessibleGraphic::getImplementationId() + throw(RuntimeException) +{ + SolarMutexGuard aGuard; + static Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accgraphic.hxx b/sw/source/core/access/accgraphic.hxx new file mode 100644 index 000000000000..18c0f67b68dc --- /dev/null +++ b/sw/source/core/access/accgraphic.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCGRAPHIC_HXX +#define _ACCGRAPHIC_HXX +#include "accnotextframe.hxx" + +class SwAccessibleGraphic : public SwAccessibleNoTextFrame +{ + +protected: + + virtual ~SwAccessibleGraphic(); + +public: + + SwAccessibleGraphic( SwAccessibleMap* pInitMap, + const SwFlyFrm *pFlyFrm ); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accheaderfooter.cxx b/sw/source/core/access/accheaderfooter.cxx new file mode 100644 index 000000000000..6472f75e9fe5 --- /dev/null +++ b/sw/source/core/access/accheaderfooter.cxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <osl/mutex.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <rtl/uuid.h> +#include <vcl/svapp.hxx> +#include <hffrm.hxx> +#include "accheaderfooter.hxx" +#include "access.hrc" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +const sal_Char sServiceNameHeader[] = "com.sun.star.text.AccessibleHeaderView"; +const sal_Char sServiceNameFooter[] = "com.sun.star.text.AccessibleFooterView"; +const sal_Char sImplementationNameHeader[] = "com.sun.star.comp.Writer.SwAccessibleHeaderView"; +const sal_Char sImplementationNameFooter[] = "com.sun.star.comp.Writer.SwAccessibleFooterView"; + +SwAccessibleHeaderFooter::SwAccessibleHeaderFooter( + SwAccessibleMap* pInitMap, + const SwHeaderFrm* pHdFrm ) : + SwAccessibleContext( pInitMap, AccessibleRole::HEADER, pHdFrm ) +{ + SolarMutexGuard aGuard; + + OUString sArg( OUString::valueOf( (sal_Int32)pHdFrm->GetPhyPageNum() ) ); + SetName( GetResource( STR_ACCESS_HEADER_NAME, &sArg ) ); +} + +SwAccessibleHeaderFooter::SwAccessibleHeaderFooter( + SwAccessibleMap* pInitMap, + const SwFooterFrm* pFtFrm ) : + SwAccessibleContext( pInitMap, AccessibleRole::FOOTER, pFtFrm ) +{ + SolarMutexGuard aGuard; + + OUString sArg( OUString::valueOf( (sal_Int32)pFtFrm->GetPhyPageNum() ) ); + SetName( GetResource( STR_ACCESS_FOOTER_NAME, &sArg ) ); +} + +SwAccessibleHeaderFooter::~SwAccessibleHeaderFooter() +{ +} + +OUString SAL_CALL SwAccessibleHeaderFooter::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + sal_uInt16 nResId = AccessibleRole::HEADER == GetRole() + ? STR_ACCESS_HEADER_DESC + : STR_ACCESS_FOOTER_DESC ; + + OUString sArg( GetFormattedPageNumber() ); + + return GetResource( nResId, &sArg ); +} + +OUString SAL_CALL SwAccessibleHeaderFooter::getImplementationName() + throw( RuntimeException ) +{ + if( AccessibleRole::HEADER == GetRole() ) + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationNameHeader)); + else + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationNameFooter)); +} + +sal_Bool SAL_CALL SwAccessibleHeaderFooter::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + if( sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ) ) + return sal_True; + else if( AccessibleRole::HEADER == GetRole() ) + return sTestServiceName.equalsAsciiL( sServiceNameHeader, sizeof(sServiceNameHeader)-1 ); + else + return sTestServiceName.equalsAsciiL( sServiceNameFooter, sizeof(sServiceNameFooter)-1 ); + +} + +Sequence< OUString > SAL_CALL SwAccessibleHeaderFooter::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + if( AccessibleRole::HEADER == GetRole() ) + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceNameHeader) ); + else + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceNameFooter) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +Sequence< sal_Int8 > SAL_CALL SwAccessibleHeaderFooter::getImplementationId() + throw(RuntimeException) +{ + SolarMutexGuard aGuard; + static Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accheaderfooter.hxx b/sw/source/core/access/accheaderfooter.hxx new file mode 100644 index 000000000000..210657e7602a --- /dev/null +++ b/sw/source/core/access/accheaderfooter.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCHEADERFOOTER_HXX +#define _ACCHEADERFOOTER_HXX +#include "acccontext.hxx" + +class SwHeaderFrm; +class SwFooterFrm; + +class SwAccessibleHeaderFooter : public SwAccessibleContext +{ + +protected: + + virtual ~SwAccessibleHeaderFooter(); + +public: + + SwAccessibleHeaderFooter( SwAccessibleMap* pInitMap, + const SwHeaderFrm* pHdFrm ); + SwAccessibleHeaderFooter( SwAccessibleMap* pInitMap, + const SwFooterFrm* pFtFrm ); + + + //===== XAccessibleContext ============================================== + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acchyperlink.cxx b/sw/source/core/access/acchyperlink.cxx new file mode 100644 index 000000000000..6b239b04e0e2 --- /dev/null +++ b/sw/source/core/access/acchyperlink.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <comphelper/accessiblekeybindinghelper.hxx> +#include <swurl.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <ndtxt.hxx> +#include <txtinet.hxx> +#include <accpara.hxx> +#include <acchyperlink.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +SwAccessibleHyperlink::SwAccessibleHyperlink( sal_uInt16 nHPos, + SwAccessibleParagraph *p, sal_Int32 nStt, sal_Int32 nEnd ) : + nHintPos( nHPos ), + xPara( p ), + nStartIdx( nStt ), + nEndIdx( nEnd ) +{ +} + +const SwTxtAttr *SwAccessibleHyperlink::GetTxtAttr() const +{ + const SwTxtAttr *pTxtAttr = 0; + if( xPara.is() && xPara->GetMap() ) + { + const SwTxtNode *pTxtNd = xPara->GetTxtNode(); + const SwpHints *pHints = pTxtNd->GetpSwpHints(); + if( pHints && nHintPos < pHints->Count() ) + { + const SwTxtAttr *pHt = (*pHints)[nHintPos]; + if( RES_TXTATR_INETFMT == pHt->Which() ) + pTxtAttr = pHt; + } + } + + return pTxtAttr; +} + + +// XAccessibleAction +sal_Int32 SAL_CALL SwAccessibleHyperlink::getAccessibleActionCount() + throw (uno::RuntimeException) +{ + return isValid() ? 1 : 0; +} + +sal_Bool SAL_CALL SwAccessibleHyperlink::doAccessibleAction( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + sal_Bool bRet = sal_False; + + const SwTxtAttr *pTxtAttr = GetTxtAttr(); + if( pTxtAttr && 0 == nIndex ) + { + const SwFmtINetFmt& rINetFmt = pTxtAttr->GetINetFmt(); + if( rINetFmt.GetValue().Len() ) + { + ViewShell *pVSh = xPara->GetShell(); + if( pVSh ) + { + LoadURL( rINetFmt.GetValue(), pVSh, URLLOAD_NOFILTER, + &rINetFmt.GetTargetFrame() ); + OSL_ENSURE( pTxtAttr == rINetFmt.GetTxtINetFmt(), + "lost my txt attr" ); + const SwTxtINetFmt* pTxtAttr2 = rINetFmt.GetTxtINetFmt(); + if( pTxtAttr2 ) + { + const_cast<SwTxtINetFmt*>(pTxtAttr2)->SetVisited(true); + const_cast<SwTxtINetFmt*>(pTxtAttr2)->SetVisitedValid(true); + } + bRet = sal_True; + } + } + } + + return bRet; +} + +OUString SAL_CALL SwAccessibleHyperlink::getAccessibleActionDescription( + sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + OUString sDesc; + + const SwTxtAttr *pTxtAttr = GetTxtAttr(); + if( pTxtAttr && 0 == nIndex ) + { + const SwFmtINetFmt& rINetFmt = pTxtAttr->GetINetFmt(); + sDesc = OUString( rINetFmt.GetValue() ); + } + + return sDesc; +} + +uno::Reference< XAccessibleKeyBinding > SAL_CALL + SwAccessibleHyperlink::getAccessibleActionKeyBinding( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + uno::Reference< XAccessibleKeyBinding > xKeyBinding; + + if( isValid() && 0==nIndex ) + { + ::comphelper::OAccessibleKeyBindingHelper* pKeyBindingHelper = + new ::comphelper::OAccessibleKeyBindingHelper(); + xKeyBinding = pKeyBindingHelper; + + awt::KeyStroke aKeyStroke; + aKeyStroke.Modifiers = 0; + aKeyStroke.KeyCode = KEY_RETURN; + aKeyStroke.KeyChar = 0; + aKeyStroke.KeyFunc = 0; + pKeyBindingHelper->AddKeyBinding( aKeyStroke ); + } + + return xKeyBinding; +} + +// XAccessibleHyperlink +uno::Any SAL_CALL SwAccessibleHyperlink::getAccessibleActionAnchor( + sal_Int32 /*nIndex*/ ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + return uno::Any(); +} + +uno::Any SAL_CALL SwAccessibleHyperlink::getAccessibleActionObject( + sal_Int32 /*nIndex*/ ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + return uno::Any(); +} + +sal_Int32 SAL_CALL SwAccessibleHyperlink::getStartIndex() + throw (uno::RuntimeException) +{ + return nStartIdx; +} + +sal_Int32 SAL_CALL SwAccessibleHyperlink::getEndIndex() + throw (uno::RuntimeException) +{ + return nEndIdx; +} + +sal_Bool SAL_CALL SwAccessibleHyperlink::isValid( ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + return xPara.is(); +} + +void SwAccessibleHyperlink::Invalidate() +{ + SolarMutexGuard aGuard; + xPara = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acchyperlink.hxx b/sw/source/core/access/acchyperlink.hxx new file mode 100644 index 000000000000..ecbaff3ec383 --- /dev/null +++ b/sw/source/core/access/acchyperlink.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCHYPERLINK_HXX +#define _ACCHYPERLINK_HXX +#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp> +#include <rtl/ref.hxx> +#include <cppuhelper/implbase1.hxx> +#include <fmtinfmt.hxx> + +class SwAccessibleParagraph; +class SwTxtAttr; + +class SwAccessibleHyperlink : + public ::cppu::WeakImplHelper1< + ::com::sun::star::accessibility::XAccessibleHyperlink > +{ + friend class SwAccessibleParagraph; + friend class SwAccessibleHyperTextData; + sal_uInt16 nHintPos; + ::rtl::Reference< SwAccessibleParagraph > xPara; + sal_Int32 nStartIdx; + sal_Int32 nEndIdx; + + SwAccessibleHyperlink( sal_uInt16 nHintPos, + SwAccessibleParagraph *p, + sal_Int32 nStt, sal_Int32 nEnd ); + + const SwTxtAttr *GetTxtAttr() const; + void Invalidate(); + +public: + + // XAccessibleAction + virtual sal_Int32 SAL_CALL getAccessibleActionCount() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL doAccessibleAction( sal_Int32 nIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleActionDescription( + sal_Int32 nIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleKeyBinding > SAL_CALL + getAccessibleActionKeyBinding( sal_Int32 nIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + // XAccessibleHyperlink + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleActionAnchor( + sal_Int32 nIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getAccessibleActionObject( + sal_Int32 nIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getStartIndex() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getEndIndex() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isValid( ) + throw (::com::sun::star::uno::RuntimeException); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acchypertextdata.cxx b/sw/source/core/access/acchypertextdata.cxx new file mode 100644 index 000000000000..2e233522aa64 --- /dev/null +++ b/sw/source/core/access/acchypertextdata.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <acchyperlink.hxx> +#include <acchypertextdata.hxx> + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; + +SwAccessibleHyperTextData::SwAccessibleHyperTextData() : + _SwAccessibleHyperlinkMap_Impl() +{ +} + +SwAccessibleHyperTextData::~SwAccessibleHyperTextData() +{ + iterator aIter = begin(); + while( aIter != end() ) + { + Reference < XAccessibleHyperlink > xTmp = (*aIter).second; + if( xTmp.is() ) + { + SwAccessibleHyperlink *pTmp = + static_cast< SwAccessibleHyperlink * >( xTmp.get() ); + pTmp->Invalidate(); + } + ++aIter; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acchypertextdata.hxx b/sw/source/core/access/acchypertextdata.hxx new file mode 100644 index 000000000000..d3d49e4e211b --- /dev/null +++ b/sw/source/core/access/acchypertextdata.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCHYPERTEXTDATA_HXX +#define _ACCHYPERTEXTDATA_HXX + +#include <cppuhelper/weakref.hxx> + +#include <map> + +class SwTxtAttr; + +namespace com { namespace sun { namespace star { + namespace accessibility { class XAccessibleHyperlink; } +} } } + +typedef ::std::less< const SwTxtAttr * > SwTxtAttrPtrLess; +typedef ::std::map < const SwTxtAttr *, ::com::sun::star::uno::WeakReference < com::sun::star::accessibility::XAccessibleHyperlink >, SwTxtAttrPtrLess > _SwAccessibleHyperlinkMap_Impl; + +class SwAccessibleHyperTextData : public _SwAccessibleHyperlinkMap_Impl +{ +public: + SwAccessibleHyperTextData(); + ~SwAccessibleHyperTextData(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accmap.cxx b/sw/source/core/access/accmap.cxx new file mode 100644 index 000000000000..a3294bc2aa01 --- /dev/null +++ b/sw/source/core/access/accmap.cxx @@ -0,0 +1,2781 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <rtl/ref.hxx> +#include <cppuhelper/weakref.hxx> +#include <vcl/window.hxx> +#include <svx/svdmodel.hxx> +#include <svx/unomod.hxx> +#include <tools/debug.hxx> + +#include <map> +#include <list> +#include <accmap.hxx> +#include <acccontext.hxx> +#include <accdoc.hxx> +#include <accpreview.hxx> +#include <accpage.hxx> +#include <accpara.hxx> +#include <accheaderfooter.hxx> +#include <accfootnote.hxx> +#include <acctextframe.hxx> +#include <accgraphic.hxx> +#include <accembedded.hxx> +#include <acccell.hxx> +#include <acctable.hxx> +#include <fesh.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> +#include <hffrm.hxx> +#include <ftnfrm.hxx> +#include <cellfrm.hxx> +#include <tabfrm.hxx> +#include <pagefrm.hxx> +#include <flyfrm.hxx> +#include <ndtyp.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <svx/ShapeTypeHandler.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <cppuhelper/implbase1.hxx> +#include <pagepreviewlayout.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <dflyobj.hxx> +#include <prevwpage.hxx> +#include <switerator.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; +using namespace ::sw::access; + +struct SwFrmFunc +{ + sal_Bool operator()( const SwFrm * p1, + const SwFrm * p2) const + { + return p1 < p2; + } +}; + +typedef ::std::map < const SwFrm *, uno::WeakReference < XAccessible >, SwFrmFunc > _SwAccessibleContextMap_Impl; + +class SwAccessibleContextMap_Impl: public _SwAccessibleContextMap_Impl +{ +public: + +#if OSL_DEBUG_LEVEL > 1 + sal_Bool mbLocked; +#endif + + SwAccessibleContextMap_Impl() +#if OSL_DEBUG_LEVEL > 1 + : mbLocked( sal_False ) +#endif + {} + +}; + +//------------------------------------------------------------------------------ +class SwDrawModellListener_Impl : public SfxListener, + public ::cppu::WeakImplHelper1< document::XEventBroadcaster > +{ + mutable ::osl::Mutex maListenerMutex; + ::cppu::OInterfaceContainerHelper maEventListeners; + SdrModel *mpDrawModel; +protected: + virtual ~SwDrawModellListener_Impl(); +public: + + SwDrawModellListener_Impl( SdrModel *pDrawModel ); + + + virtual void SAL_CALL addEventListener( const uno::Reference< document::XEventListener >& xListener ) throw (uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const uno::Reference< document::XEventListener >& xListener ) throw (uno::RuntimeException); + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + void Dispose(); +}; + +SwDrawModellListener_Impl::SwDrawModellListener_Impl( SdrModel *pDrawModel ) : + maEventListeners( maListenerMutex ), + mpDrawModel( pDrawModel ) +{ + StartListening( *mpDrawModel ); +} + +SwDrawModellListener_Impl::~SwDrawModellListener_Impl() +{ + EndListening( *mpDrawModel ); +} + +void SAL_CALL SwDrawModellListener_Impl::addEventListener( const uno::Reference< document::XEventListener >& xListener ) throw (uno::RuntimeException) +{ + maEventListeners.addInterface( xListener ); +} + +void SAL_CALL SwDrawModellListener_Impl::removeEventListener( const uno::Reference< document::XEventListener >& xListener ) throw (uno::RuntimeException) +{ + maEventListeners.removeInterface( xListener ); +} + +void SwDrawModellListener_Impl::Notify( SfxBroadcaster& /*rBC*/, + const SfxHint& rHint ) +{ + // do not broadcast notifications for writer fly frames, because there + // are no shapes that need to know about them. + const SdrHint *pSdrHint = PTR_CAST( SdrHint, &rHint ); + if ( !pSdrHint || + ( pSdrHint->GetObject() && + ( pSdrHint->GetObject()->ISA(SwFlyDrawObj) || + pSdrHint->GetObject()->ISA(SwVirtFlyDrawObj) || + IS_TYPE(SdrObject,pSdrHint->GetObject()) ) ) ) + { + return; + } + + OSL_ENSURE( mpDrawModel, "draw model listener is disposed" ); + if( !mpDrawModel ) + return; + + document::EventObject aEvent; + if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) ) + return; + + ::cppu::OInterfaceIteratorHelper aIter( maEventListeners ); + while( aIter.hasMoreElements() ) + { + uno::Reference < document::XEventListener > xListener( aIter.next(), + uno::UNO_QUERY ); + try + { + xListener->notifyEvent( aEvent ); + } + catch( uno::RuntimeException const & r ) + { + (void)r; +#if OSL_DEBUG_LEVEL > 1 + ByteString aError( "Runtime exception caught while notifying shape.:\n" ); + aError += ByteString( String( r.Message), RTL_TEXTENCODING_ASCII_US ); + OSL_FAIL( aError.GetBuffer() ); +#endif + } + } +} + +void SwDrawModellListener_Impl::Dispose() +{ + mpDrawModel = 0; +} + +//------------------------------------------------------------------------------ +struct SwShapeFunc +{ + sal_Bool operator()( const SdrObject * p1, + const SdrObject * p2) const + { + return p1 < p2; + } +}; +typedef ::std::map < const SdrObject *, uno::WeakReference < XAccessible >, SwShapeFunc > _SwAccessibleShapeMap_Impl; +typedef ::std::pair < const SdrObject *, ::rtl::Reference < ::accessibility::AccessibleShape > > SwAccessibleObjShape_Impl; + +class SwAccessibleShapeMap_Impl: public _SwAccessibleShapeMap_Impl + +{ + ::accessibility::AccessibleShapeTreeInfo maInfo; + +public: + +#if OSL_DEBUG_LEVEL > 1 + sal_Bool mbLocked; +#endif + SwAccessibleShapeMap_Impl( SwAccessibleMap *pMap ) +#if OSL_DEBUG_LEVEL > 1 + : mbLocked( sal_False ) +#endif + { + maInfo.SetSdrView( pMap->GetShell()->GetDrawView() ); + maInfo.SetWindow( pMap->GetShell()->GetWin() ); + maInfo.SetViewForwarder( pMap ); + uno::Reference < document::XEventBroadcaster > xModelBroadcaster = + new SwDrawModellListener_Impl( + pMap->GetShell()->getIDocumentDrawModelAccess()->GetOrCreateDrawModel() ); + maInfo.SetControllerBroadcaster( xModelBroadcaster ); + } + + ~SwAccessibleShapeMap_Impl(); + + const ::accessibility::AccessibleShapeTreeInfo& GetInfo() const { return maInfo; } + + SwAccessibleObjShape_Impl *Copy( size_t& rSize, + const SwFEShell *pFESh = 0, + SwAccessibleObjShape_Impl **pSelShape = 0 ) const; +}; + +SwAccessibleShapeMap_Impl::~SwAccessibleShapeMap_Impl() +{ + uno::Reference < document::XEventBroadcaster > xBrd( maInfo.GetControllerBroadcaster() ); + if( xBrd.is() ) + static_cast < SwDrawModellListener_Impl * >( xBrd.get() )->Dispose(); +} + +SwAccessibleObjShape_Impl + *SwAccessibleShapeMap_Impl::Copy( + size_t& rSize, const SwFEShell *pFESh, + SwAccessibleObjShape_Impl **pSelStart ) const +{ + SwAccessibleObjShape_Impl *pShapes = 0; + SwAccessibleObjShape_Impl *pSelShape = 0; + + sal_uInt16 nSelShapes = pFESh ? pFESh->IsObjSelected() : 0; + rSize = size(); + + if( rSize > 0 ) + { + pShapes = + new SwAccessibleObjShape_Impl[rSize]; + + const_iterator aIter = begin(); + const_iterator aEndIter = end(); + + SwAccessibleObjShape_Impl *pShape = pShapes; + pSelShape = &(pShapes[rSize]); + while( aIter != aEndIter ) + { + const SdrObject *pObj = (*aIter).first; + uno::Reference < XAccessible > xAcc( (*aIter).second ); + if( nSelShapes && pFESh->IsObjSelected( *pObj ) ) + { + // selected objects are inserted from the back + --pSelShape; + pSelShape->first = pObj; + pSelShape->second = + static_cast < ::accessibility::AccessibleShape* >( + xAcc.get() ); + --nSelShapes; + } + else + { + pShape->first = pObj; + pShape->second = + static_cast < ::accessibility::AccessibleShape* >( + xAcc.get() ); + ++pShape; + } + ++aIter; + } + OSL_ENSURE( pSelShape == pShape, "copying shapes went wrong!" ); + } + + if( pSelStart ) + *pSelStart = pSelShape; + + return pShapes; +} + +//------------------------------------------------------------------------------ +struct SwAccessibleEvent_Impl +{ +public: + enum EventType { CARET_OR_STATES, + INVALID_CONTENT, + POS_CHANGED, + CHILD_POS_CHANGED, + SHAPE_SELECTION, + DISPOSE, + INVALID_ATTR }; + +private: + SwRect maOldBox; // the old bounds for CHILD_POS_CHANGED + // and POS_CHANGED + uno::WeakReference < XAccessible > mxAcc; // The object that fires the event + SwAccessibleChild maFrmOrObj; // the child for CHILD_POS_CHANGED and + // the same as xAcc for any other + // event type + EventType meType; // The event type + tAccessibleStates mnStates; // check states or update caret pos + + SwAccessibleEvent_Impl& operator==( const SwAccessibleEvent_Impl& ); + +public: + SwAccessibleEvent_Impl( EventType eT, + SwAccessibleContext *pA, + const SwAccessibleChild& rFrmOrObj ) + : mxAcc( pA ), + maFrmOrObj( rFrmOrObj ), + meType( eT ), + mnStates( 0 ) + {} + + SwAccessibleEvent_Impl( EventType eT, + const SwAccessibleChild& rFrmOrObj ) + : maFrmOrObj( rFrmOrObj ), + meType( eT ), + mnStates( 0 ) + { + OSL_ENSURE( SwAccessibleEvent_Impl::DISPOSE == meType, + "wrong event constructor, DISPOSE only" ); + } + + SwAccessibleEvent_Impl( EventType eT ) + : meType( eT ), + mnStates( 0 ) + { + OSL_ENSURE( SwAccessibleEvent_Impl::SHAPE_SELECTION == meType, + "wrong event constructor, SHAPE_SELECTION only" ); + } + + SwAccessibleEvent_Impl( EventType eT, + SwAccessibleContext *pA, + const SwAccessibleChild& rFrmOrObj, + const SwRect& rR ) + : maOldBox( rR ), + mxAcc( pA ), + maFrmOrObj( rFrmOrObj ), + meType( eT ), + mnStates( 0 ) + { + OSL_ENSURE( SwAccessibleEvent_Impl::CHILD_POS_CHANGED == meType || + SwAccessibleEvent_Impl::POS_CHANGED == meType, + "wrong event constructor, (CHILD_)POS_CHANGED only" ); + } + + SwAccessibleEvent_Impl( EventType eT, + SwAccessibleContext *pA, + const SwAccessibleChild& rFrmOrObj, + const tAccessibleStates _nStates ) + : mxAcc( pA ), + maFrmOrObj( rFrmOrObj ), + meType( eT ), + mnStates( _nStates ) + { + OSL_ENSURE( SwAccessibleEvent_Impl::CARET_OR_STATES == meType, + "wrong event constructor, CARET_OR_STATES only" ); + } + + // <SetType(..)> only used in method <SwAccessibleMap::AppendEvent(..)> + inline void SetType( EventType eT ) + { + meType = eT; + } + inline EventType GetType() const + { + return meType; + } + + inline ::rtl::Reference < SwAccessibleContext > GetContext() const + { + uno::Reference < XAccessible > xTmp( mxAcc ); + ::rtl::Reference < SwAccessibleContext > xAccImpl( + static_cast<SwAccessibleContext*>( xTmp.get() ) ); + + return xAccImpl; + } + + inline const SwRect& GetOldBox() const + { + return maOldBox; + } + // <SetOldBox(..)> only used in method <SwAccessibleMap::AppendEvent(..)> + inline void SetOldBox( const SwRect& rOldBox ) + { + maOldBox = rOldBox; + } + + inline const SwAccessibleChild& GetFrmOrObj() const + { + return maFrmOrObj; + } + + // <SetStates(..)> only used in method <SwAccessibleMap::AppendEvent(..)> + inline void SetStates( tAccessibleStates _nStates ) + { + mnStates |= _nStates; + } + + inline sal_Bool IsUpdateCursorPos() const + { + return (mnStates & ACC_STATE_CARET) != 0; + } + inline sal_Bool IsInvalidateStates() const + { + return (mnStates & ACC_STATE_MASK) != 0; + } + inline sal_Bool IsInvalidateRelation() const + { + return (mnStates & ACC_STATE_RELATION_MASK) != 0; + } + inline sal_Bool IsInvalidateTextSelection() const + { + return ( mnStates & ACC_STATE_TEXT_SELECTION_CHANGED ) != 0; + } + + inline sal_Bool IsInvalidateTextAttrs() const + { + return ( mnStates & ACC_STATE_TEXT_ATTRIBUTE_CHANGED ) != 0; + } + + inline tAccessibleStates GetStates() const + { + return mnStates & ACC_STATE_MASK; + } + + inline tAccessibleStates GetAllStates() const + { + return mnStates; + } + +}; + +//------------------------------------------------------------------------------ +typedef ::std::list < SwAccessibleEvent_Impl > _SwAccessibleEventList_Impl; + +class SwAccessibleEventList_Impl: public _SwAccessibleEventList_Impl +{ + sal_Bool mbFiring; + +public: + + SwAccessibleEventList_Impl() + : mbFiring( sal_False ) + {} + + inline void SetFiring() + { + mbFiring = sal_True; + } + inline sal_Bool IsFiring() const + { + return mbFiring; + } +}; + +//------------------------------------------------------------------------------ +// The shape list is filled if an accessible shape is destroyed. It +// simply keeps a reference to the accessible shape's XShape. These +// references are destroyed within the EndAction when firing events, +// There are twp reason for this. First of all, a new accessible shape +// for the XShape might be created soon. It's then cheaper if the XShape +// still exists. The other reason are situations where an accessible shape +// is destroyed within an SwFrmFmt::Modify. In this case, destryoing +// the XShape at the same time (indirectly by destroying the accessible +// shape) leads to an assert, because a client of the Modify is destroyed +// within a Modify call. + +typedef ::std::list < uno::Reference < drawing::XShape > > _SwShapeList_Impl; + +class SwShapeList_Impl: public _SwShapeList_Impl +{ +public: + + SwShapeList_Impl() {} +}; + + +//------------------------------------------------------------------------------ +struct SwAccessibleChildFunc +{ + sal_Bool operator()( const SwAccessibleChild& r1, + const SwAccessibleChild& r2 ) const + { + const void *p1 = r1.GetSwFrm() + ? static_cast < const void * >( r1.GetSwFrm()) + : ( r1.GetDrawObject() + ? static_cast < const void * >( r1.GetDrawObject() ) + : static_cast < const void * >( r1.GetWindow() ) ); + const void *p2 = r2.GetSwFrm() + ? static_cast < const void * >( r2.GetSwFrm()) + : ( r2.GetDrawObject() + ? static_cast < const void * >( r2.GetDrawObject() ) + : static_cast < const void * >( r2.GetWindow() ) ); + return p1 < p2; + } +}; +typedef ::std::map < SwAccessibleChild, SwAccessibleEventList_Impl::iterator, + SwAccessibleChildFunc > _SwAccessibleEventMap_Impl; + +class SwAccessibleEventMap_Impl: public _SwAccessibleEventMap_Impl +{ +}; + +//------------------------------------------------------------------------------ + +struct SwAccessibleParaSelection +{ + xub_StrLen nStartOfSelection; + xub_StrLen nEndOfSelection; + + SwAccessibleParaSelection( const xub_StrLen _nStartOfSelection, + const xub_StrLen _nEndOfSelection ) + : nStartOfSelection( _nStartOfSelection ), + nEndOfSelection( _nEndOfSelection ) + {} +}; + +struct SwXAccWeakRefComp +{ + sal_Bool operator()( const uno::WeakReference<XAccessible>& _rXAccWeakRef1, + const uno::WeakReference<XAccessible>& _rXAccWeakRef2 ) const + { + return _rXAccWeakRef1.get() < _rXAccWeakRef2.get(); + } +}; + +typedef ::std::map< uno::WeakReference < XAccessible >, + SwAccessibleParaSelection, + SwXAccWeakRefComp > _SwAccessibleSelectedParas_Impl; + +class SwAccessibleSelectedParas_Impl: public _SwAccessibleSelectedParas_Impl +{}; + +// helper class that stores preview data +class SwAccPreviewData +{ + typedef std::vector<Rectangle> Rectangles; + Rectangles maPreviewRects; + Rectangles maLogicRects; + + SwRect maVisArea; + Fraction maScale; + + const SwPageFrm *mpSelPage; + + /** adjust logic page retangle to its visible part + + @param _iorLogicPgSwRect + input/output parameter - reference to the logic page rectangle, which + has to be adjusted. + + @param _rPrevwPgSwRect + input parameter - constant reference to the corresponding preview page + rectangle; needed to determine the visible part of the logic page rectangle. + + @param _rPrevwWinSize + input paramter - constant reference to the preview window size in TWIP; + needed to determine the visible part of the logic page rectangle + */ + void AdjustLogicPgRectToVisibleArea( SwRect& _iorLogicPgSwRect, + const SwRect& _rPrevwPgSwRect, + const Size& _rPrevwWinSize ); + +public: + SwAccPreviewData(); + ~SwAccPreviewData(); + + void Update( const SwAccessibleMap& rAccMap, + const std::vector<PrevwPage*>& _rPrevwPages, + const Fraction& _rScale, + const SwPageFrm* _pSelectedPageFrm, + const Size& _rPrevwWinSize ); + + void InvalidateSelection( const SwPageFrm* _pSelectedPageFrm ); + + const SwRect& GetVisArea() const; + + MapMode GetMapModeForPreview( ) const; + + /** Adjust the MapMode so that the preview page appears at the + * proper position. rPoint identifies the page for which the + * MapMode should be adjusted. If bFromPreview is true, rPoint is + * a preview coordinate; else it's a document coordinate. */ + void AdjustMapMode( MapMode& rMapMode, + const Point& rPoint ) const; + + inline const SwPageFrm *GetSelPage() const { return mpSelPage; } + + void DisposePage(const SwPageFrm *pPageFrm ); +}; + +SwAccPreviewData::SwAccPreviewData() : + mpSelPage( 0 ) +{ +} + +SwAccPreviewData::~SwAccPreviewData() +{ +} + +void SwAccPreviewData::Update( const SwAccessibleMap& rAccMap, + const std::vector<PrevwPage*>& _rPrevwPages, + const Fraction& _rScale, + const SwPageFrm* _pSelectedPageFrm, + const Size& _rPrevwWinSize ) +{ + // store preview scaling, maximal preview page size and selected page + maScale = _rScale; + mpSelPage = _pSelectedPageFrm; + + // prepare loop on preview pages + maPreviewRects.clear(); + maLogicRects.clear(); + SwAccessibleChild aPage; + maVisArea.Clear(); + + // loop on preview pages to calculate <maPreviewRects>, <maLogicRects> and + // <maVisArea> + for ( std::vector<PrevwPage*>::const_iterator aPageIter = _rPrevwPages.begin(); + aPageIter != _rPrevwPages.end(); + ++aPageIter ) + { + aPage = (*aPageIter)->pPage; + + // add preview page rectangle to <maPreviewRects> + Rectangle aPrevwPgRect( (*aPageIter)->aPrevwWinPos, (*aPageIter)->aPageSize ); + maPreviewRects.push_back( aPrevwPgRect ); + + // add logic page rectangle to <maLogicRects> + SwRect aLogicPgSwRect( aPage.GetBox( rAccMap ) ); + Rectangle aLogicPgRect( aLogicPgSwRect.SVRect() ); + maLogicRects.push_back( aLogicPgRect ); + // union visible area with visible part of logic page rectangle + if ( (*aPageIter)->bVisible ) + { + if ( !(*aPageIter)->pPage->IsEmptyPage() ) + { + AdjustLogicPgRectToVisibleArea( aLogicPgSwRect, + SwRect( aPrevwPgRect ), + _rPrevwWinSize ); + } + if ( maVisArea.IsEmpty() ) + maVisArea = aLogicPgSwRect; + else + maVisArea.Union( aLogicPgSwRect ); + } + } +} + +void SwAccPreviewData::InvalidateSelection( const SwPageFrm* _pSelectedPageFrm ) +{ + mpSelPage = _pSelectedPageFrm; + OSL_ENSURE( mpSelPage, "selected page not found" ); +} + +struct ContainsPredicate +{ + const Point& mrPoint; + ContainsPredicate( const Point& rPoint ) : mrPoint(rPoint) {} + bool operator() ( const Rectangle& rRect ) const + { + return rRect.IsInside( mrPoint ) ? true : false; + } +}; + +const SwRect& SwAccPreviewData::GetVisArea() const +{ + return maVisArea; +} + +void SwAccPreviewData::AdjustMapMode( MapMode& rMapMode, + const Point& rPoint ) const +{ + // adjust scale + rMapMode.SetScaleX( maScale ); + rMapMode.SetScaleY( maScale ); + + // find proper rectangle + Rectangles::const_iterator aBegin = maLogicRects.begin(); + Rectangles::const_iterator aEnd = maLogicRects.end(); + Rectangles::const_iterator aFound = ::std::find_if( aBegin, aEnd, + ContainsPredicate( rPoint ) ); + + if( aFound != aEnd ) + { + // found! set new origin + Point aPoint = (maPreviewRects.begin() + (aFound - aBegin))->TopLeft(); + aPoint -= (maLogicRects.begin() + (aFound-aBegin))->TopLeft(); + rMapMode.SetOrigin( aPoint ); + } + // else: don't adjust MapMode +} + +void SwAccPreviewData::DisposePage(const SwPageFrm *pPageFrm ) +{ + if( mpSelPage == pPageFrm ) + mpSelPage = 0; +} + +// adjust logic page retangle to its visible part +void SwAccPreviewData::AdjustLogicPgRectToVisibleArea( + SwRect& _iorLogicPgSwRect, + const SwRect& _rPrevwPgSwRect, + const Size& _rPrevwWinSize ) +{ + // determine preview window rectangle + const SwRect aPrevwWinSwRect( Point( 0, 0 ), _rPrevwWinSize ); + // calculate visible preview page rectangle + SwRect aVisPrevwPgSwRect( _rPrevwPgSwRect ); + aVisPrevwPgSwRect.Intersection( aPrevwWinSwRect ); + // adjust logic page rectangle + SwTwips nTmpDiff; + // left + nTmpDiff = aVisPrevwPgSwRect.Left() - _rPrevwPgSwRect.Left(); + if ( nTmpDiff > 0 ) + _iorLogicPgSwRect.Left( _iorLogicPgSwRect.Left() + nTmpDiff ); + // top + nTmpDiff = aVisPrevwPgSwRect.Top() - _rPrevwPgSwRect.Top(); + if ( nTmpDiff > 0 ) + _iorLogicPgSwRect.Top( _iorLogicPgSwRect.Top() + nTmpDiff ); + // right + nTmpDiff = _rPrevwPgSwRect.Right() - aVisPrevwPgSwRect.Right(); + if ( nTmpDiff > 0 ) + _iorLogicPgSwRect.Right( _iorLogicPgSwRect.Right() - nTmpDiff ); + // bottom + nTmpDiff = _rPrevwPgSwRect.Bottom() - aVisPrevwPgSwRect.Bottom(); + if ( nTmpDiff > 0 ) + _iorLogicPgSwRect.Bottom( _iorLogicPgSwRect.Bottom() - nTmpDiff ); +} + +//------------------------------------------------------------------------------ +static sal_Bool AreInSameTable( const uno::Reference< XAccessible >& rAcc, + const SwFrm *pFrm ) +{ + sal_Bool bRet = sal_False; + + if( pFrm && pFrm->IsCellFrm() && rAcc.is() ) + { + // Is it in the same table? We check that + // by comparing the last table frame in the + // follow chain, because that's cheaper than + // searching the first one. + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( rAcc.get() ); + if( pAccImpl->GetFrm()->IsCellFrm() ) + { + const SwTabFrm *pTabFrm1 = pAccImpl->GetFrm()->FindTabFrm(); + while( pTabFrm1->GetFollow() ) + pTabFrm1 = pTabFrm1->GetFollow(); + + const SwTabFrm *pTabFrm2 = pFrm->FindTabFrm(); + while( pTabFrm2->GetFollow() ) + pTabFrm2 = pTabFrm2->GetFollow(); + + bRet = (pTabFrm1 == pTabFrm2); + } + } + + return bRet; +} + +void SwAccessibleMap::FireEvent( const SwAccessibleEvent_Impl& rEvent ) +{ + ::rtl::Reference < SwAccessibleContext > xAccImpl( rEvent.GetContext() ); + if( SwAccessibleEvent_Impl::SHAPE_SELECTION == rEvent.GetType() ) + { + DoInvalidateShapeSelection(); + } + else if( xAccImpl.is() && xAccImpl->GetFrm() ) + { + if ( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE && + rEvent.IsInvalidateTextAttrs() ) + { + xAccImpl->InvalidateAttr(); + } + switch( rEvent.GetType() ) + { + case SwAccessibleEvent_Impl::INVALID_CONTENT: + xAccImpl->InvalidateContent(); + break; + case SwAccessibleEvent_Impl::POS_CHANGED: + xAccImpl->InvalidatePosOrSize( rEvent.GetOldBox() ); + break; + case SwAccessibleEvent_Impl::CHILD_POS_CHANGED: + xAccImpl->InvalidateChildPosOrSize( rEvent.GetFrmOrObj(), + rEvent.GetOldBox() ); + break; + case SwAccessibleEvent_Impl::DISPOSE: + OSL_ENSURE( xAccImpl.is(), + "dispose event has been stored" ); + break; + case SwAccessibleEvent_Impl::INVALID_ATTR: + // nothing to do here - handled above + break; + default: + break; + } + if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() ) + { + if( rEvent.IsUpdateCursorPos() ) + xAccImpl->InvalidateCursorPos(); + if( rEvent.IsInvalidateStates() ) + xAccImpl->InvalidateStates( rEvent.GetStates() ); + if( rEvent.IsInvalidateRelation() ) + { + // both events CONTENT_FLOWS_FROM_RELATION_CHANGED and + // CONTENT_FLOWS_TO_RELATION_CHANGED are possible + if ( rEvent.GetAllStates() & ACC_STATE_RELATION_FROM ) + { + xAccImpl->InvalidateRelation( + AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED ); + } + if ( rEvent.GetAllStates() & ACC_STATE_RELATION_TO ) + { + xAccImpl->InvalidateRelation( + AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED ); + } + } + + if ( rEvent.IsInvalidateTextSelection() ) + { + xAccImpl->InvalidateTextSelection(); + } + } + } +} + +void SwAccessibleMap::AppendEvent( const SwAccessibleEvent_Impl& rEvent ) +{ + osl::MutexGuard aGuard( maEventMutex ); + + if( !mpEvents ) + mpEvents = new SwAccessibleEventList_Impl; + if( !mpEventMap ) + mpEventMap = new SwAccessibleEventMap_Impl; + + if( mpEvents->IsFiring() ) + { + // While events are fired new ones are generated. They have to be fired + // now. This does not work for DISPOSE events! + OSL_ENSURE( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE, + "dispose event while firing events" ); + FireEvent( rEvent ); + } + else + { + + SwAccessibleEventMap_Impl::iterator aIter = + mpEventMap->find( rEvent.GetFrmOrObj() ); + if( aIter != mpEventMap->end() ) + { + SwAccessibleEvent_Impl aEvent( *(*aIter).second ); + OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE, + "dispose events should not be stored" ); + sal_Bool bAppendEvent = sal_True; + switch( rEvent.GetType() ) + { + case SwAccessibleEvent_Impl::CARET_OR_STATES: + // A CARET_OR_STATES event is added to any other + // event only. It is broadcasted after any other event, so the + // event should be put to the back. + OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED, + "invalid event combination" ); + aEvent.SetStates( rEvent.GetAllStates() ); + break; + case SwAccessibleEvent_Impl::INVALID_CONTENT: + // An INVALID_CONTENT event overwrites a CARET_OR_STATES + // event (but keeps its flags) and it is contained in a + // POS_CHANGED event. + // Therefor, the event's type has to be adapted and the event + // has to be put at the end. + OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED, + "invalid event combination" ); + if( aEvent.GetType() == SwAccessibleEvent_Impl::CARET_OR_STATES ) + aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT ); + break; + case SwAccessibleEvent_Impl::POS_CHANGED: + // A pos changed event overwrites CARET_STATES (keeping its + // flags) as well as INVALID_CONTENT. The old box position + // has to be stored however if the old event is not a + // POS_CHANGED itself. + OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED, + "invalid event combination" ); + if( aEvent.GetType() != SwAccessibleEvent_Impl::POS_CHANGED ) + aEvent.SetOldBox( rEvent.GetOldBox() ); + aEvent.SetType( SwAccessibleEvent_Impl::POS_CHANGED ); + break; + case SwAccessibleEvent_Impl::CHILD_POS_CHANGED: + // CHILD_POS_CHANGED events can only follow CHILD_POS_CHANGED + // events. The only action that needs to be done again is + // to put the old event to the back. The new one cannot be used, + // because we are interested in the old frame bounds. + OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::CHILD_POS_CHANGED, + "invalid event combination" ); + break; + case SwAccessibleEvent_Impl::SHAPE_SELECTION: + OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::SHAPE_SELECTION, + "invalid event combination" ); + break; + case SwAccessibleEvent_Impl::DISPOSE: + // DISPOSE events overwrite all others. They are not stored + // but executed immediatly to avoid broadcasting of + // defunctional objects. So what needs to be done here is to + // remove all events for the frame in question. + bAppendEvent = sal_False; + break; + case SwAccessibleEvent_Impl::INVALID_ATTR: + OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR, + "invalid event combination" ); + break; + } + if( bAppendEvent ) + { + mpEvents->erase( (*aIter).second ); + (*aIter).second = mpEvents->insert( mpEvents->end(), aEvent ); + } + else + { + mpEvents->erase( (*aIter).second ); + mpEventMap->erase( aIter ); + } + } + else if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() ) + { + SwAccessibleEventMap_Impl::value_type aEntry( rEvent.GetFrmOrObj(), + mpEvents->insert( mpEvents->end(), rEvent ) ); + mpEventMap->insert( aEntry ); + } + } +} + +void SwAccessibleMap::InvalidateCursorPosition( + const uno::Reference< XAccessible >& rAcc ) +{ + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( rAcc.get() ); + OSL_ENSURE( pAccImpl, "no caret context" ); + OSL_ENSURE( pAccImpl->GetFrm(), "caret context is disposed" ); + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES, + pAccImpl, + SwAccessibleChild(pAccImpl->GetFrm()), + ACC_STATE_CARET ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + // While firing events the current frame might have + // been disposed because it moved out of the vis area. + // Setting the cursor for such frames is useless and even + // causes asserts. + if( pAccImpl->GetFrm() ) + pAccImpl->InvalidateCursorPos(); + } +} + +void SwAccessibleMap::InvalidateShapeSelection() +{ + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( + SwAccessibleEvent_Impl::SHAPE_SELECTION ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + DoInvalidateShapeSelection(); + } +} + +void SwAccessibleMap::DoInvalidateShapeSelection() +{ + SwAccessibleObjShape_Impl *pShapes = 0; + SwAccessibleObjShape_Impl *pSelShape = 0; + size_t nShapes = 0; + + const ViewShell *pVSh = GetShell(); + const SwFEShell *pFESh = pVSh->ISA( SwFEShell ) ? + static_cast< const SwFEShell * >( pVSh ) : 0; + sal_uInt16 nSelShapes = pFESh ? pFESh->IsObjSelected() : 0; + + { + osl::MutexGuard aGuard( maMutex ); + if( mpShapeMap ) + pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape ); + } + + if( pShapes ) + { + ::std::list< const SwFrm * > aParents; + Window *pWin = GetShell()->GetWin(); + sal_Bool bFocused = pWin && pWin->HasFocus(); + SwAccessibleObjShape_Impl *pShape = pShapes; + while( nShapes ) + { + if( pShape->second.is() ) + { + sal_Bool bChanged; + if( pShape >= pSelShape ) + { + bChanged = + pShape->second->SetState( AccessibleStateType::SELECTED ); + if( bFocused && 1 == nSelShapes ) + pShape->second->SetState( AccessibleStateType::FOCUSED ); + else + pShape->second->ResetState( AccessibleStateType::FOCUSED ); + } + else + { + bChanged = + pShape->second->ResetState( AccessibleStateType::SELECTED ); + pShape->second->ResetState( AccessibleStateType::FOCUSED ); + } + if( bChanged ) + { + const SwFrm* pParent = SwAccessibleFrame::GetParent( + SwAccessibleChild( pShape->first ), + GetShell()->IsPreView() ); + aParents.push_back( pParent ); + } + } + + --nShapes; + ++pShape; + } + if( aParents.size() > 0 ) + { + ::std::list< const SwFrm * >::const_iterator aIter = aParents.begin(); + ::std::list< const SwFrm * >::const_iterator aEndIter = aParents.end(); + while( aIter != aEndIter ) + { + ::rtl::Reference< SwAccessibleContext > xParentAccImpl; + { + osl::MutexGuard aGuard( maMutex ); + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::const_iterator aMapIter = + mpFrmMap->find( *aIter ); + if( aMapIter != mpFrmMap->end() ) + { + uno::Reference < XAccessible > xAcc( (*aMapIter).second ); + xParentAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + } + } + } + if( xParentAccImpl.is() ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; + xParentAccImpl->FireAccessibleEvent( aEvent ); + } + + ++aIter; + } + } + + delete[] pShapes; + } +} + +void SwAccessibleMap::DoInvalidateShapeFocus() +{ + const ViewShell *pVSh = GetShell(); + const SwFEShell *pFESh = pVSh->ISA( SwFEShell ) ? + static_cast< const SwFEShell * >( pVSh ) : 0; + sal_uInt16 nSelShapes = pFESh ? pFESh->IsObjSelected() : 0; + + if( nSelShapes != 1 ) + return; + + SwAccessibleObjShape_Impl *pShapes = 0; + SwAccessibleObjShape_Impl *pSelShape = 0; + size_t nShapes = 0; + + + { + osl::MutexGuard aGuard( maMutex ); + if( mpShapeMap ) + pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape ); + } + + if( pShapes ) + { + Window *pWin = GetShell()->GetWin(); + sal_Bool bFocused = pWin && pWin->HasFocus(); + SwAccessibleObjShape_Impl *pShape = pShapes; + while( nShapes ) + { + if( pShape->second.is() ) + { + if( bFocused && pShape >= pSelShape ) + pShape->second->SetState( AccessibleStateType::FOCUSED ); + else + pShape->second->ResetState( AccessibleStateType::FOCUSED ); + } + + --nShapes; + ++pShape; + } + + delete[] pShapes; + } +} + + +SwAccessibleMap::SwAccessibleMap( ViewShell *pSh ) : + mpFrmMap( 0 ), + mpShapeMap( 0 ), + mpShapes( 0 ), + mpEvents( 0 ), + mpEventMap( 0 ), + mpSelectedParas( 0 ), + mpVSh( pSh ), + mpPreview( 0 ), + mnPara( 1 ), + mnFootnote( 1 ), + mnEndnote( 1 ), + mbShapeSelected( sal_False ) +{ + pSh->GetLayout()->AddAccessibleShell(); +} + +SwAccessibleMap::~SwAccessibleMap() +{ + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + if( mpFrmMap ) + { + const SwRootFrm *pRootFrm = GetShell()->GetLayout(); + SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->find( pRootFrm ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + if( !xAcc.is() ) + xAcc = new SwAccessibleDocument( this ); + } + } + + SwAccessibleDocument *pAcc = + static_cast< SwAccessibleDocument * >( xAcc.get() ); + pAcc->Dispose( sal_True ); + + { + osl::MutexGuard aGuard( maMutex ); +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( !mpFrmMap || mpFrmMap->empty(), + "Frame map should be empty after disposing the root frame" ); + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->begin(); + while( aIter != mpFrmMap->end() ) + { + uno::Reference < XAccessible > xTmp = (*aIter).second; + if( xTmp.is() ) + { + SwAccessibleContext *pTmp = + static_cast< SwAccessibleContext * >( xTmp.get() ); + (void) pTmp; + } + ++aIter; + } + } + OSL_ENSURE( !mpShapeMap || mpShapeMap->empty(), + "Object map should be empty after disposing the root frame" ); + if( mpShapeMap ) + { + SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->begin(); + while( aIter != mpShapeMap->end() ) + { + uno::Reference < XAccessible > xTmp = (*aIter).second; + if( xTmp.is() ) + { + ::accessibility::AccessibleShape *pTmp = + static_cast< ::accessibility::AccessibleShape* >( xTmp.get() ); + (void) pTmp; + } + ++aIter; + } + } +#endif + delete mpFrmMap; + mpFrmMap = 0; + delete mpShapeMap; + mpShapeMap = 0; + delete mpShapes; + mpShapes = 0; + delete mpSelectedParas; + mpSelectedParas = 0; + } + + delete mpPreview; + mpPreview = NULL; + + { + osl::MutexGuard aGuard( maEventMutex ); +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( !(mpEvents || mpEventMap), "pending events" ); + if( mpEvents ) + { + SwAccessibleEventList_Impl::iterator aIter = mpEvents->begin(); + while( aIter != mpEvents->end() ) + { + ++aIter; + } + } + if( mpEventMap ) + { + SwAccessibleEventMap_Impl::iterator aIter = mpEventMap->begin(); + while( aIter != mpEventMap->end() ) + { + ++aIter; + } + } +#endif + delete mpEventMap; + mpEventMap = 0; + delete mpEvents; + mpEvents = 0; + } + mpVSh->GetLayout()->RemoveAccessibleShell(); +} + +uno::Reference< XAccessible > SwAccessibleMap::_GetDocumentView( + sal_Bool bPagePreview ) +{ + uno::Reference < XAccessible > xAcc; + sal_Bool bSetVisArea = sal_False; + + { + osl::MutexGuard aGuard( maMutex ); + + if( !mpFrmMap ) + { + mpFrmMap = new SwAccessibleContextMap_Impl; +#if OSL_DEBUG_LEVEL > 1 + mpFrmMap->mbLocked = sal_False; +#endif + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( !mpFrmMap->mbLocked, "Map is locked" ); + mpFrmMap->mbLocked = sal_True; +#endif + + const SwRootFrm *pRootFrm = GetShell()->GetLayout(); + SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->find( pRootFrm ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + if( xAcc.is() ) + { + bSetVisArea = sal_True; // Set VisArea when map mutex is not + // locked + } + else + { + if( bPagePreview ) + xAcc = new SwAccessiblePreview( this ); + else + xAcc = new SwAccessibleDocument( this ); + + if( aIter != mpFrmMap->end() ) + { + (*aIter).second = xAcc; + } + else + { + SwAccessibleContextMap_Impl::value_type aEntry( pRootFrm, xAcc ); + mpFrmMap->insert( aEntry ); + } + } + +#if OSL_DEBUG_LEVEL > 1 + mpFrmMap->mbLocked = sal_False; +#endif + } + + if( bSetVisArea ) + { + SwAccessibleDocumentBase *pAcc = + static_cast< SwAccessibleDocumentBase * >( xAcc.get() ); + pAcc->SetVisArea(); + } + + return xAcc; +} + +uno::Reference< XAccessible > SwAccessibleMap::GetDocumentView( ) +{ + return _GetDocumentView( sal_False ); +} + +uno::Reference<XAccessible> SwAccessibleMap::GetDocumentPreview( + const std::vector<PrevwPage*>& _rPrevwPages, + const Fraction& _rScale, + const SwPageFrm* _pSelectedPageFrm, + const Size& _rPrevwWinSize ) +{ + // create & update preview data object + if( mpPreview == NULL ) + mpPreview = new SwAccPreviewData(); + mpPreview->Update( *this, _rPrevwPages, _rScale, _pSelectedPageFrm, _rPrevwWinSize ); + + uno::Reference<XAccessible> xAcc = _GetDocumentView( sal_True ); + return xAcc; +} + +uno::Reference< XAccessible> SwAccessibleMap::GetContext( const SwFrm *pFrm, + sal_Bool bCreate ) +{ + uno::Reference < XAccessible > xAcc; + uno::Reference < XAccessible > xOldCursorAcc; + sal_Bool bOldShapeSelected = sal_False; + + { + osl::MutexGuard aGuard( maMutex ); + + if( !mpFrmMap && bCreate ) + mpFrmMap = new SwAccessibleContextMap_Impl; + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->find( pFrm ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + + if( !xAcc.is() && bCreate ) + { + SwAccessibleContext *pAcc = 0; + switch( pFrm->GetType() ) + { + case FRM_TXT: + mnPara++; + pAcc = new SwAccessibleParagraph( *this, + static_cast< const SwTxtFrm& >( *pFrm ) ); + break; + case FRM_HEADER: + pAcc = new SwAccessibleHeaderFooter( this, + static_cast< const SwHeaderFrm *>( pFrm ) ); + break; + case FRM_FOOTER: + pAcc = new SwAccessibleHeaderFooter( this, + static_cast< const SwFooterFrm *>( pFrm ) ); + break; + case FRM_FTN: + { + const SwFtnFrm *pFtnFrm = + static_cast < const SwFtnFrm * >( pFrm ); + sal_Bool bIsEndnote = + SwAccessibleFootnote::IsEndnote( pFtnFrm ); + pAcc = new SwAccessibleFootnote( this, bIsEndnote, + (bIsEndnote ? mnEndnote++ : mnFootnote++), + pFtnFrm ); + } + break; + case FRM_FLY: + { + const SwFlyFrm *pFlyFrm = + static_cast < const SwFlyFrm * >( pFrm ); + switch( SwAccessibleFrameBase::GetNodeType( pFlyFrm ) ) + { + case ND_GRFNODE: + pAcc = new SwAccessibleGraphic( this, pFlyFrm ); + break; + case ND_OLENODE: + pAcc = new SwAccessibleEmbeddedObject( this, pFlyFrm ); + break; + default: + pAcc = new SwAccessibleTextFrame( this, pFlyFrm ); + break; + } + } + break; + case FRM_CELL: + pAcc = new SwAccessibleCell( this, + static_cast< const SwCellFrm *>( pFrm ) ); + break; + case FRM_TAB: + pAcc = new SwAccessibleTable( this, + static_cast< const SwTabFrm *>( pFrm ) ); + break; + case FRM_PAGE: + DBG_ASSERT( GetShell()->IsPreView(), + "accessible page frames only in PagePreview" ); + pAcc = new SwAccessiblePage( this, pFrm ); + break; + } + xAcc = pAcc; + + OSL_ENSURE( xAcc.is(), "unknown frame type" ); + if( xAcc.is() ) + { + if( aIter != mpFrmMap->end() ) + { + (*aIter).second = xAcc; + } + else + { + SwAccessibleContextMap_Impl::value_type aEntry( pFrm, xAcc ); + mpFrmMap->insert( aEntry ); + } + + if( pAcc->HasCursor() && + !AreInSameTable( mxCursorContext, pFrm ) ) + { + // If the new context has the focus, and if we know + // another context that had the focus, then the focus + // just moves from the old context to the new one. We + // have to send a focus event and a caret event for + // the old context then. We have to to that know, + // because after we have left this method, anyone might + // call getStates for the new context and will get a + // focused state then. Sending the focus changes event + // after that seems to be strange. However, we cannot + // send a focus event fo the new context now, because + // noone except us knows it. In any case, we remeber + // the new context as the one that has the focus + // currently. + + xOldCursorAcc = mxCursorContext; + mxCursorContext = xAcc; + + bOldShapeSelected = mbShapeSelected; + mbShapeSelected = sal_False; + } + } + } + } + } + + // Invalidate focus for old object when map is not locked + if( xOldCursorAcc.is() ) + InvalidateCursorPosition( xOldCursorAcc ); + if( bOldShapeSelected ) + InvalidateShapeSelection(); + + return xAcc; +} + +::rtl::Reference < SwAccessibleContext > SwAccessibleMap::GetContextImpl( + const SwFrm *pFrm, + sal_Bool bCreate ) +{ + uno::Reference < XAccessible > xAcc( GetContext( pFrm, bCreate ) ); + + ::rtl::Reference < SwAccessibleContext > xAccImpl( + static_cast< SwAccessibleContext * >( xAcc.get() ) ); + + return xAccImpl; +} + +uno::Reference< XAccessible> SwAccessibleMap::GetContext( + const SdrObject *pObj, + SwAccessibleContext *pParentImpl, + sal_Bool bCreate ) +{ + uno::Reference < XAccessible > xAcc; + uno::Reference < XAccessible > xOldCursorAcc; + + { + osl::MutexGuard aGuard( maMutex ); + + if( !mpShapeMap && bCreate ) + mpShapeMap = new SwAccessibleShapeMap_Impl( this ); + if( mpShapeMap ) + { + SwAccessibleShapeMap_Impl::iterator aIter = + mpShapeMap->find( pObj ); + if( aIter != mpShapeMap->end() ) + xAcc = (*aIter).second; + + if( !xAcc.is() && bCreate ) + { + ::accessibility::AccessibleShape *pAcc = 0; + uno::Reference < drawing::XShape > xShape( + const_cast< SdrObject * >( pObj )->getUnoShape(), + uno::UNO_QUERY ); + if( xShape.is() ) + { + ::accessibility::ShapeTypeHandler& rShapeTypeHandler = + ::accessibility::ShapeTypeHandler::Instance(); + uno::Reference < XAccessible > xParent( pParentImpl ); + ::accessibility::AccessibleShapeInfo aShapeInfo( + xShape, xParent, this ); + + pAcc = rShapeTypeHandler.CreateAccessibleObject( + aShapeInfo, mpShapeMap->GetInfo() ); + } + xAcc = pAcc; + + OSL_ENSURE( xAcc.is(), "unknown shape type" ); + if( xAcc.is() ) + { + pAcc->Init(); + if( aIter != mpShapeMap->end() ) + { + (*aIter).second = xAcc; + } + else + { + SwAccessibleShapeMap_Impl::value_type aEntry( pObj, + xAcc ); + mpShapeMap->insert( aEntry ); + } + // TODO: focus!!! + } + } + } + } + + // Invalidate focus for old object when map is not locked + if( xOldCursorAcc.is() ) + InvalidateCursorPosition( xOldCursorAcc ); + + return xAcc; +} + +::rtl::Reference < ::accessibility::AccessibleShape > SwAccessibleMap::GetContextImpl( + const SdrObject *pObj, + SwAccessibleContext *pParentImpl, + sal_Bool bCreate ) +{ + uno::Reference < XAccessible > xAcc( GetContext( pObj, pParentImpl, bCreate ) ); + + ::rtl::Reference < ::accessibility::AccessibleShape > xAccImpl( + static_cast< ::accessibility::AccessibleShape* >( xAcc.get() ) ); + + return xAccImpl; +} + + +void SwAccessibleMap::RemoveContext( const SwFrm *pFrm ) +{ + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( pFrm ); + if( aIter != mpFrmMap->end() ) + { + mpFrmMap->erase( aIter ); + + // Remove reference to old caret object. Though mxCursorContext + // is a weak reference and cleared automatically, clearing it + // directly makes sure to not keep a defunctional object. + uno::Reference < XAccessible > xOldAcc( mxCursorContext ); + if( xOldAcc.is() ) + { + SwAccessibleContext *pOldAccImpl = + static_cast< SwAccessibleContext *>( xOldAcc.get() ); + OSL_ENSURE( pOldAccImpl->GetFrm(), "old caret context is disposed" ); + if( pOldAccImpl->GetFrm() == pFrm ) + { + xOldAcc.clear(); // get an empty ref + mxCursorContext = xOldAcc; + } + } + + if( mpFrmMap->empty() ) + { + delete mpFrmMap; + mpFrmMap = 0; + } + } + } +} + +void SwAccessibleMap::RemoveContext( const SdrObject *pObj ) +{ + osl::MutexGuard aGuard( maMutex ); + + if( mpShapeMap ) + { + SwAccessibleShapeMap_Impl::iterator aIter = + mpShapeMap->find( pObj ); + if( aIter != mpShapeMap->end() ) + { + mpShapeMap->erase( aIter ); + + // The shape selection flag is not cleared, but one might do + // so but has to make sure that the removed context is the one + // that is selected. + + if( mpShapeMap->empty() ) + { + delete mpShapeMap; + mpShapeMap = 0; + } + } + } +} + + +void SwAccessibleMap::Dispose( const SwFrm *pFrm, + const SdrObject *pObj, + Window* pWindow, + sal_Bool bRecursive ) +{ + SwAccessibleChild aFrmOrObj( pFrm, pObj, pWindow ); + + // Indeed, the following assert checks the frame's accessible flag, + // because that's the one that is evaluated in the layout. The frame + // might not be accessible anyway. That's the case for cell frames that + // contain further cells. + OSL_ENSURE( !aFrmOrObj.GetSwFrm() || aFrmOrObj.GetSwFrm()->IsAccessibleFrm(), + "non accessible frame should be disposed" ); + + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl; + ::rtl::Reference< SwAccessibleContext > xParentAccImpl; + ::rtl::Reference< ::accessibility::AccessibleShape > xShapeAccImpl; + // get accessible context for frame + { + osl::MutexGuard aGuard( maMutex ); + + // First of all look for an accessible context for a frame + if( aFrmOrObj.GetSwFrm() && mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + { + uno::Reference < XAccessible > xAcc( (*aIter).second ); + xAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + } + } + if( !xAccImpl.is() && mpFrmMap ) + { + // If there is none, look if the parent is accessible. + const SwFrm *pParent = + SwAccessibleFrame::GetParent( aFrmOrObj, + GetShell()->IsPreView()); + + if( pParent ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( pParent ); + if( aIter != mpFrmMap->end() ) + { + uno::Reference < XAccessible > xAcc( (*aIter).second ); + xParentAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + } + } + } + if( !xParentAccImpl.is() && !aFrmOrObj.GetSwFrm() && + mpShapeMap ) + { + SwAccessibleShapeMap_Impl::iterator aIter = + mpShapeMap->find( aFrmOrObj.GetDrawObject() ); + if( aIter != mpShapeMap->end() ) + { + uno::Reference < XAccessible > xAcc( (*aIter).second ); + xShapeAccImpl = + static_cast< ::accessibility::AccessibleShape *>( xAcc.get() ); + } + } + if( pObj && GetShell()->ActionPend() && + (xParentAccImpl.is() || xShapeAccImpl.is()) ) + { + // Keep a reference to the XShape to avoid that it + // is deleted with a SwFrmFmt::Modify. + uno::Reference < drawing::XShape > xShape( + const_cast< SdrObject * >( pObj )->getUnoShape(), + uno::UNO_QUERY ); + if( xShape.is() ) + { + if( !mpShapes ) + mpShapes = new SwShapeList_Impl; + mpShapes->push_back( xShape ); + } + } + } + + // remove events stored for the frame + { + osl::MutexGuard aGuard( maEventMutex ); + if( mpEvents ) + { + SwAccessibleEventMap_Impl::iterator aIter = + mpEventMap->find( aFrmOrObj ); + if( aIter != mpEventMap->end() ) + { + SwAccessibleEvent_Impl aEvent( + SwAccessibleEvent_Impl::DISPOSE, aFrmOrObj ); + AppendEvent( aEvent ); + } + } + } + + // If the frame is accessible and there is a context for it, dispose + // the frame. If the frame is no context for it but disposing should + // take place recursive, the frame's children have to be disposed + // anyway, so we have to create the context then. + if( xAccImpl.is() ) + { + xAccImpl->Dispose( bRecursive ); + } + else if( xParentAccImpl.is() ) + { + // If the frame is a cell frame, the table must be notified. + // If we are in an action, a table model change event will + // be broadcasted at the end of the action to give the table + // a chance to generate a single table change event. + + xParentAccImpl->DisposeChild( aFrmOrObj, bRecursive ); + } + else if( xShapeAccImpl.is() ) + { + RemoveContext( aFrmOrObj.GetDrawObject() ); + xShapeAccImpl->dispose(); + } + + if( mpPreview && pFrm && pFrm->IsPageFrm() ) + mpPreview->DisposePage( static_cast< const SwPageFrm *>( pFrm ) ); + } +} + +void SwAccessibleMap::InvalidatePosOrSize( const SwFrm *pFrm, + const SdrObject *pObj, + Window* pWindow, + const SwRect& rOldBox ) +{ + SwAccessibleChild aFrmOrObj( pFrm, pObj, pWindow ); + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + ::rtl::Reference< SwAccessibleContext > xAccImpl; + ::rtl::Reference< SwAccessibleContext > xParentAccImpl; + { + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + if( aFrmOrObj.GetSwFrm() ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + { + // If there is an accesible object already it is + // notified directly. + uno::Reference < XAccessible > xAcc( (*aIter).second ); + xAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + } + } + if( !xAccImpl.is() ) + { + // Otherwise we look if the parent is accessible. + // If not, there is nothing to do. + const SwFrm *pParent = + SwAccessibleFrame::GetParent( aFrmOrObj, + GetShell()->IsPreView()); + + if( pParent ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( pParent ); + if( aIter != mpFrmMap->end() ) + { + uno::Reference < XAccessible > xAcc( (*aIter).second ); + xParentAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + } + } + } + } + } + + if( xAccImpl.is() ) + { + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( + SwAccessibleEvent_Impl::POS_CHANGED, xAccImpl.get(), + aFrmOrObj, rOldBox ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + xAccImpl->InvalidatePosOrSize( rOldBox ); + } + } + else if( xParentAccImpl.is() ) + { + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( + SwAccessibleEvent_Impl::CHILD_POS_CHANGED, + xParentAccImpl.get(), aFrmOrObj, rOldBox ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + xParentAccImpl->InvalidateChildPosOrSize( aFrmOrObj, + rOldBox ); + } + } + } +} + +void SwAccessibleMap::InvalidateContent( const SwFrm *pFrm ) +{ + SwAccessibleChild aFrmOrObj( pFrm ); + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + } + } + + if( xAcc.is() ) + { + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( + SwAccessibleEvent_Impl::INVALID_CONTENT, pAccImpl, + aFrmOrObj ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + pAccImpl->InvalidateContent(); + } + } + } +} + +void SwAccessibleMap::InvalidateAttr( const SwTxtFrm& rTxtFrm ) +{ + SwAccessibleChild aFrmOrObj( &rTxtFrm ); + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + } + } + + if( xAcc.is() ) + { + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::INVALID_ATTR, + pAccImpl, aFrmOrObj ); + aEvent.SetStates( ACC_STATE_TEXT_ATTRIBUTE_CHANGED ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + pAccImpl->InvalidateAttr(); + } + } + } +} + +void SwAccessibleMap::InvalidateCursorPosition( const SwFrm *pFrm ) +{ + SwAccessibleChild aFrmOrObj( pFrm ); + sal_Bool bShapeSelected = sal_False; + const ViewShell *pVSh = GetShell(); + if( pVSh->ISA( SwCrsrShell ) ) + { + const SwCrsrShell *pCSh = static_cast< const SwCrsrShell * >( pVSh ); + if( pCSh->IsTableMode() ) + { + while( aFrmOrObj.GetSwFrm() && !aFrmOrObj.GetSwFrm()->IsCellFrm() ) + aFrmOrObj = aFrmOrObj.GetSwFrm()->GetUpper(); + } + else if( pVSh->ISA( SwFEShell ) ) + { + const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh ); + const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm(); + if( pFlyFrm ) + { + OSL_ENSURE( !pFrm || pFrm->FindFlyFrm() == pFlyFrm, + "cursor is not contained in fly frame" ); + aFrmOrObj = pFlyFrm; + } + else if( pFESh->IsObjSelected() > 0 ) + { + bShapeSelected = sal_True; + aFrmOrObj = static_cast<const SwFrm *>( 0 ); + } + } + } + + OSL_ENSURE( bShapeSelected || aFrmOrObj.IsAccessible(GetShell()->IsPreView()), + "frame is not accessible" ); + + uno::Reference < XAccessible > xOldAcc; + uno::Reference < XAccessible > xAcc; + sal_Bool bOldShapeSelected = sal_False; + + { + osl::MutexGuard aGuard( maMutex ); + + xOldAcc = mxCursorContext; + mxCursorContext = xAcc; // clear reference + + bOldShapeSelected = mbShapeSelected; + mbShapeSelected = bShapeSelected; + + if( aFrmOrObj.GetSwFrm() && mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + + // For cells, some extra thoughts are necessary, + // because invalidating the cursor for one cell + // invalidates the cursor for all cells of the same + // table. For this reason, we don't want to + // invalidate the cursor for the old cursor object + // and the new one if they are within the same table, + // because this would result in doing the work twice. + // Moreover, we have to make sure to invalidate the + // cursor even if the current cell has no accessible object. + // If the old cursor objects exists and is in the same + // table, its the best choice, because using it avoids + // an unnessarary cursor invalidation cycle when creating + // a new object for the current cell. + if( aFrmOrObj.GetSwFrm()->IsCellFrm() ) + { + if( xOldAcc.is() && + AreInSameTable( xOldAcc, aFrmOrObj.GetSwFrm() ) ) + { + if( xAcc.is() ) + xOldAcc = xAcc; // avoid extra invalidation + else + xAcc = xOldAcc; // make sure ate least one + } + if( !xAcc.is() ) + xAcc = GetContext( aFrmOrObj.GetSwFrm(), sal_True ); + } + } + } + + if( xOldAcc.is() && xOldAcc != xAcc ) + InvalidateCursorPosition( xOldAcc ); + if( bOldShapeSelected || bShapeSelected ) + InvalidateShapeSelection(); + if( xAcc.is() ) + InvalidateCursorPosition( xAcc ); +} + +void SwAccessibleMap::InvalidateFocus() +{ + uno::Reference < XAccessible > xAcc; + sal_Bool bShapeSelected; + { + osl::MutexGuard aGuard( maMutex ); + + xAcc = mxCursorContext; + bShapeSelected = mbShapeSelected; + } + + if( xAcc.is() ) + { + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + pAccImpl->InvalidateFocus(); + } + else if( bShapeSelected ) + { + DoInvalidateShapeFocus(); + } +} + +void SwAccessibleMap::SetCursorContext( + const ::rtl::Reference < SwAccessibleContext >& rCursorContext ) +{ + osl::MutexGuard aGuard( maMutex ); + uno::Reference < XAccessible > xAcc( rCursorContext.get() ); + mxCursorContext = xAcc; +} + +void SwAccessibleMap::InvalidateStates( tAccessibleStates _nStates, + const SwFrm* _pFrm ) +{ + // Start with the frame or the first upper that is accessible + SwAccessibleChild aFrmOrObj( _pFrm ); + while( aFrmOrObj.GetSwFrm() && + !aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + aFrmOrObj = aFrmOrObj.GetSwFrm()->GetUpper(); + if( !aFrmOrObj.GetSwFrm() ) + aFrmOrObj = GetShell()->GetLayout(); + + uno::Reference< XAccessible > xAcc( GetContext( aFrmOrObj.GetSwFrm(), sal_True ) ); + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES, + pAccImpl, + SwAccessibleChild(pAccImpl->GetFrm()), + _nStates ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + pAccImpl->InvalidateStates( _nStates ); + } +} + +void SwAccessibleMap::_InvalidateRelationSet( const SwFrm* pFrm, + sal_Bool bFrom ) +{ + // first, see if this frame is accessible, and if so, get the respective + SwAccessibleChild aFrmOrObj( pFrm ); + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + { + xAcc = (*aIter).second; + } + } + } + + // deliver event directly, or queue event + if( xAcc.is() ) + { + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES, + pAccImpl, SwAccessibleChild(pFrm), + ( bFrom + ? ACC_STATE_RELATION_FROM + : ACC_STATE_RELATION_TO ) ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + pAccImpl->InvalidateRelation( bFrom + ? AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED + : AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED ); + } + } + } +} + +void SwAccessibleMap::InvalidateRelationSet( const SwFrm* pMaster, + const SwFrm* pFollow ) +{ + _InvalidateRelationSet( pMaster, sal_False ); + _InvalidateRelationSet( pFollow, sal_True ); +} + +// invalidation of CONTENT_FLOW_FROM/_TO relation of a paragraph +void SwAccessibleMap::InvalidateParaFlowRelation( const SwTxtFrm& _rTxtFrm, + const bool _bFrom ) +{ + _InvalidateRelationSet( &_rTxtFrm, _bFrom ); +} + +// invalidation of text selection of a paragraph +void SwAccessibleMap::InvalidateParaTextSelection( const SwTxtFrm& _rTxtFrm ) +{ + // first, see if this frame is accessible, and if so, get the respective + SwAccessibleChild aFrmOrObj( &_rTxtFrm ); + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + { + xAcc = (*aIter).second; + } + } + } + + // deliver event directly, or queue event + if( xAcc.is() ) + { + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + if( GetShell()->ActionPend() ) + { + SwAccessibleEvent_Impl aEvent( + SwAccessibleEvent_Impl::CARET_OR_STATES, + pAccImpl, + SwAccessibleChild( &_rTxtFrm ), + ACC_STATE_TEXT_SELECTION_CHANGED ); + AppendEvent( aEvent ); + } + else + { + FireEvents(); + pAccImpl->InvalidateTextSelection(); + } + } + } +} + +sal_Int32 SwAccessibleMap::GetChildIndex( const SwFrm& rParentFrm, + Window& rChild ) const +{ + sal_Int32 nIndex( -1 ); + + SwAccessibleChild aFrmOrObj( &rParentFrm ); + if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) ) + { + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + if( mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( aFrmOrObj.GetSwFrm() ); + if( aIter != mpFrmMap->end() ) + { + xAcc = (*aIter).second; + } + } + } + + if( xAcc.is() ) + { + SwAccessibleContext *pAccImpl = + static_cast< SwAccessibleContext *>( xAcc.get() ); + + nIndex = pAccImpl->GetChildIndex( const_cast<SwAccessibleMap&>(*this), + SwAccessibleChild( &rChild ) ); + } + } + + return nIndex; +} + +void SwAccessibleMap::UpdatePreview( const std::vector<PrevwPage*>& _rPrevwPages, + const Fraction& _rScale, + const SwPageFrm* _pSelectedPageFrm, + const Size& _rPrevwWinSize ) +{ + DBG_ASSERT( GetShell()->IsPreView(), "no preview?" ); + DBG_ASSERT( mpPreview != NULL, "no preview data?" ); + + mpPreview->Update( *this, _rPrevwPages, _rScale, _pSelectedPageFrm, _rPrevwWinSize ); + + // propagate change of VisArea through the document's + // accessibility tree; this will also send appropriate scroll + // events + SwAccessibleContext* pDoc = + GetContextImpl( GetShell()->GetLayout() ).get(); + static_cast<SwAccessibleDocumentBase*>( pDoc )->SetVisArea(); + + uno::Reference < XAccessible > xOldAcc; + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + xOldAcc = mxCursorContext; + + const SwPageFrm *pSelPage = mpPreview->GetSelPage(); + if( pSelPage && mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( pSelPage ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + } + } + + if( xOldAcc.is() && xOldAcc != xAcc ) + InvalidateCursorPosition( xOldAcc ); + if( xAcc.is() ) + InvalidateCursorPosition( xAcc ); +} + +void SwAccessibleMap::InvalidatePreViewSelection( sal_uInt16 nSelPage ) +{ + DBG_ASSERT( GetShell()->IsPreView(), "no preview?" ); + DBG_ASSERT( mpPreview != NULL, "no preview data?" ); + + mpPreview->InvalidateSelection( GetShell()->GetLayout()->GetPageByPageNum( nSelPage ) ); + + uno::Reference < XAccessible > xOldAcc; + uno::Reference < XAccessible > xAcc; + { + osl::MutexGuard aGuard( maMutex ); + + xOldAcc = mxCursorContext; + + const SwPageFrm *pSelPage = mpPreview->GetSelPage(); + if( pSelPage && mpFrmMap ) + { + SwAccessibleContextMap_Impl::iterator aIter = + mpFrmMap->find( pSelPage ); + if( aIter != mpFrmMap->end() ) + xAcc = (*aIter).second; + } + } + + if( xOldAcc.is() && xOldAcc != xAcc ) + InvalidateCursorPosition( xOldAcc ); + if( xAcc.is() ) + InvalidateCursorPosition( xAcc ); +} + + +sal_Bool SwAccessibleMap::IsPageSelected( const SwPageFrm *pPageFrm ) const +{ + return mpPreview && mpPreview->GetSelPage() == pPageFrm; +} + + +void SwAccessibleMap::FireEvents() +{ + { + osl::MutexGuard aGuard( maEventMutex ); + if( mpEvents ) + { + mpEvents->SetFiring(); + SwAccessibleEventList_Impl::iterator aIter = mpEvents->begin(); + while( aIter != mpEvents->end() ) + { + FireEvent( *aIter ); + ++aIter; + } + + delete mpEventMap; + mpEventMap = 0; + + delete mpEvents; + mpEvents = 0; + } + } + { + osl::MutexGuard aGuard( maMutex ); + if( mpShapes ) + { + delete mpShapes; + mpShapes = 0; + } + } + +} + +sal_Bool SwAccessibleMap::IsValid() const +{ + return sal_True; +} + +Rectangle SwAccessibleMap::GetVisibleArea() const +{ + MapMode aSrc( MAP_TWIP ); + MapMode aDest( MAP_100TH_MM ); + return OutputDevice::LogicToLogic( GetVisArea().SVRect(), aSrc, aDest ); +} + +// Convert a MM100 value realtive to the document root into a pixel value +// realtive to the screen! +Point SwAccessibleMap::LogicToPixel( const Point& rPoint ) const +{ + MapMode aSrc( MAP_100TH_MM ); + MapMode aDest( MAP_TWIP ); + + Point aPoint = rPoint; + + aPoint = OutputDevice::LogicToLogic( aPoint, aSrc, aDest ); + Window *pWin = GetShell()->GetWin(); + if( pWin ) + { + MapMode aMapMode; + GetMapMode( aPoint, aMapMode ); + aPoint = pWin->LogicToPixel( aPoint, aMapMode ); + aPoint = pWin->OutputToAbsoluteScreenPixel( aPoint ); + } + + return aPoint; +} + +Size SwAccessibleMap::LogicToPixel( const Size& rSize ) const +{ + MapMode aSrc( MAP_100TH_MM ); + MapMode aDest( MAP_TWIP ); + Size aSize( OutputDevice::LogicToLogic( rSize, aSrc, aDest ) ); + if( GetShell()->GetWin() ) + { + MapMode aMapMode; + GetMapMode( Point(0,0), aMapMode ); + aSize = GetShell()->GetWin()->LogicToPixel( aSize, aMapMode ); + } + + return aSize; +} + +Point SwAccessibleMap::PixelToLogic( const Point& rPoint ) const +{ + Point aPoint; + Window *pWin = GetShell()->GetWin(); + if( pWin ) + { + aPoint = pWin->ScreenToOutputPixel( rPoint ); + MapMode aMapMode; + GetMapMode( aPoint, aMapMode ); + aPoint = pWin->PixelToLogic( aPoint, aMapMode ); + MapMode aSrc( MAP_TWIP ); + MapMode aDest( MAP_100TH_MM ); + aPoint = OutputDevice::LogicToLogic( aPoint, aSrc, aDest ); + } + + return aPoint; +} + +Size SwAccessibleMap::PixelToLogic( const Size& rSize ) const +{ + Size aSize; + if( GetShell()->GetWin() ) + { + MapMode aMapMode; + GetMapMode( Point(0,0), aMapMode ); + aSize = GetShell()->GetWin()->PixelToLogic( rSize, aMapMode ); + MapMode aSrc( MAP_TWIP ); + MapMode aDest( MAP_100TH_MM ); + aSize = OutputDevice::LogicToLogic( aSize, aSrc, aDest ); + } + + return aSize; +} + +sal_Bool SwAccessibleMap::ReplaceChild ( + ::accessibility::AccessibleShape* pCurrentChild, + const uno::Reference< drawing::XShape >& _rxShape, + const long /*_nIndex*/, + const ::accessibility::AccessibleShapeTreeInfo& /*_rShapeTreeInfo*/ + ) throw (uno::RuntimeException) +{ + const SdrObject *pObj = 0; + { + osl::MutexGuard aGuard( maMutex ); + if( mpShapeMap ) + { + SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->begin(); + SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->end(); + while( aIter != aEndIter && !pObj ) + { + uno::Reference < XAccessible > xAcc( (*aIter).second ); + ::accessibility::AccessibleShape *pAccShape = + static_cast < ::accessibility::AccessibleShape* >( xAcc.get() ); + if( pAccShape == pCurrentChild ) + { + pObj = (*aIter).first; + } + ++aIter; + } + } + } + if( !pObj ) + return sal_False; + + uno::Reference < drawing::XShape > xShape( _rxShape ); //keep reference to shape, because + // we might be the only one that + // hold it. + // Also get keep parent. + uno::Reference < XAccessible > xParent( pCurrentChild->getAccessibleParent() ); + pCurrentChild = 0; // well be realease by dispose + Dispose( 0, pObj, 0 ); + + { + osl::MutexGuard aGuard( maMutex ); + + if( !mpShapeMap ) + mpShapeMap = new SwAccessibleShapeMap_Impl( this ); + + // create the new child + ::accessibility::ShapeTypeHandler& rShapeTypeHandler = + ::accessibility::ShapeTypeHandler::Instance(); + ::accessibility::AccessibleShapeInfo aShapeInfo( + xShape, xParent, this ); + ::accessibility::AccessibleShape* pReplacement = + rShapeTypeHandler.CreateAccessibleObject ( + aShapeInfo, mpShapeMap->GetInfo() ); + + uno::Reference < XAccessible > xAcc( pReplacement ); + if( xAcc.is() ) + { + pReplacement->Init(); + + SwAccessibleShapeMap_Impl::iterator aIter = + mpShapeMap->find( pObj ); + if( aIter != mpShapeMap->end() ) + { + (*aIter).second = xAcc; + } + else + { + SwAccessibleShapeMap_Impl::value_type aEntry( pObj, xAcc ); + mpShapeMap->insert( aEntry ); + } + } + } + + SwRect aEmptyRect; + InvalidatePosOrSize( 0, pObj, 0, aEmptyRect ); + + return sal_True; +} + +Point SwAccessibleMap::PixelToCore( const Point& rPoint ) const +{ + Point aPoint; + if( GetShell()->GetWin() ) + { + MapMode aMapMode; + GetMapMode( rPoint, aMapMode ); + aPoint = GetShell()->GetWin()->PixelToLogic( rPoint, aMapMode ); + } + return aPoint; +} + +static inline long lcl_CorrectCoarseValue(long aCoarseValue, long aFineValue, + long aRefValue, bool bToLower) +{ + long aResult = aCoarseValue; + + if (bToLower) + { + if (aFineValue < aRefValue) + aResult -= 1; + } + else + { + if (aFineValue > aRefValue) + aResult += 1; + } + + return aResult; +} + +static inline void lcl_CorrectRectangle(Rectangle & rRect, + const Rectangle & rSource, + const Rectangle & rInGrid) +{ + rRect.nLeft = lcl_CorrectCoarseValue(rRect.nLeft, rSource.nLeft, + rInGrid.nLeft, false); + rRect.nTop = lcl_CorrectCoarseValue(rRect.nTop, rSource.nTop, + rInGrid.nTop, false); + rRect.nRight = lcl_CorrectCoarseValue(rRect.nRight, rSource.nRight, + rInGrid.nRight, true); + rRect.nBottom = lcl_CorrectCoarseValue(rRect.nBottom, rSource.nBottom, + rInGrid.nBottom, true); +} + +Rectangle SwAccessibleMap::CoreToPixel( const Rectangle& rRect ) const +{ + Rectangle aRect; + if( GetShell()->GetWin() ) + { + MapMode aMapMode; + GetMapMode( rRect.TopLeft(), aMapMode ); + aRect = GetShell()->GetWin()->LogicToPixel( rRect, aMapMode ); + + Rectangle aTmpRect = GetShell()->GetWin()->PixelToLogic( aRect, aMapMode ); + lcl_CorrectRectangle(aRect, rRect, aTmpRect); + } + + return aRect; +} + +/** get mapping mode for LogicToPixel and PixelToLogic conversions + + Method returns mapping mode of current output device and adjusts it, + if the shell is in page/print preview. + Necessary, because <PreviewAdjust(..)> changes mapping mode at current + output device for mapping logic document positions to page preview window + positions and vice versa and doesn't take care to recover its changes. +*/ +void SwAccessibleMap::GetMapMode( const Point& _rPoint, + MapMode& _orMapMode ) const +{ + MapMode aMapMode = GetShell()->GetWin()->GetMapMode(); + if( GetShell()->IsPreView() ) + { + DBG_ASSERT( mpPreview != NULL, "need preview data" ); + + mpPreview->AdjustMapMode( aMapMode, _rPoint ); + } + _orMapMode = aMapMode; +} + +Size SwAccessibleMap::GetPreViewPageSize( sal_uInt16 _nPrevwPageNum ) const +{ + DBG_ASSERT( mpVSh->IsPreView(), "no page preview accessible." ); + DBG_ASSERT( mpVSh->IsPreView() && ( mpPreview != NULL ), + "missing accessible preview data at page preview" ); + if ( mpVSh->IsPreView() && ( mpPreview != NULL ) ) + { + return mpVSh->PagePreviewLayout()->GetPrevwPageSizeByPageNum( _nPrevwPageNum ); + } + else + { + return Size( 0, 0 ); + } +} + +/** method to build up a new data structure of the accessible pararaphs, + which have a selection + Important note: method has to used inside a mutual exclusive section +*/ +SwAccessibleSelectedParas_Impl* SwAccessibleMap::_BuildSelectedParas() +{ + // no accessible contexts, no selection + if ( !mpFrmMap ) + { + return 0L; + } + + // get cursor as an instance of its base class <SwPaM> + SwPaM* pCrsr( 0L ); + { + SwCrsrShell* pCrsrShell = dynamic_cast<SwCrsrShell*>(GetShell()); + if ( pCrsrShell ) + { + SwFEShell* pFEShell = dynamic_cast<SwFEShell*>(pCrsrShell); + if ( !pFEShell || + ( !pFEShell->IsFrmSelected() && + pFEShell->IsObjSelected() == 0 ) ) + { + // get cursor without updating an existing table cursor. + pCrsr = pCrsrShell->GetCrsr( sal_False ); + } + } + } + // no cursor, no selection + if ( !pCrsr ) + { + return 0L; + } + + SwAccessibleSelectedParas_Impl* pRetSelectedParas( 0L ); + + // loop on all cursors + SwPaM* pRingStart = pCrsr; + do { + + // for a selection the cursor has to have a mark. + // for savety reasons assure that point and mark are in text nodes + if ( pCrsr->HasMark() && + pCrsr->GetPoint()->nNode.GetNode().IsTxtNode() && + pCrsr->GetMark()->nNode.GetNode().IsTxtNode() ) + { + SwPosition* pStartPos = pCrsr->Start(); + SwPosition* pEndPos = pCrsr->End(); + // loop on all text nodes inside the selection + SwNodeIndex aIdx( pStartPos->nNode ); + for ( ; aIdx.GetIndex() <= pEndPos->nNode.GetIndex(); ++aIdx ) + { + SwTxtNode* pTxtNode( aIdx.GetNode().GetTxtNode() ); + if ( pTxtNode ) + { + // loop on all text frames registered at the text node. + SwIterator<SwTxtFrm,SwTxtNode> aIter( *pTxtNode ); + for( SwTxtFrm* pTxtFrm = aIter.First(); pTxtFrm; pTxtFrm = aIter.Next() ) + { + uno::WeakReference < XAccessible > xWeakAcc; + SwAccessibleContextMap_Impl::iterator aMapIter = + mpFrmMap->find( pTxtFrm ); + if( aMapIter != mpFrmMap->end() ) + { + xWeakAcc = (*aMapIter).second; + SwAccessibleParaSelection aDataEntry( + pTxtNode == &(pStartPos->nNode.GetNode()) + ? pStartPos->nContent.GetIndex() + : 0, + pTxtNode == &(pEndPos->nNode.GetNode()) + ? pEndPos->nContent.GetIndex() + : STRING_LEN ); + SwAccessibleSelectedParas_Impl::value_type + aEntry( xWeakAcc, aDataEntry ); + if ( !pRetSelectedParas ) + { + pRetSelectedParas = + new SwAccessibleSelectedParas_Impl; + } + pRetSelectedParas->insert( aEntry ); + } + } + } + } + } + + // prepare next turn: get next cursor in ring + pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() ); + } while ( pCrsr != pRingStart ); + + return pRetSelectedParas; +} + +void SwAccessibleMap::InvalidateTextSelectionOfAllParas() +{ + osl::MutexGuard aGuard( maMutex ); + + // keep previously known selected paragraphs + SwAccessibleSelectedParas_Impl* pPrevSelectedParas( mpSelectedParas ); + + // determine currently selected paragraphs + mpSelectedParas = _BuildSelectedParas(); + + // compare currently selected paragraphs with the previously selected + // paragraphs and submit corresponding TEXT_SELECTION_CHANGED events. + // first, search for new and changed selections. + // on the run remove selections from previously known ones, if they are + // also in the current ones. + if ( mpSelectedParas ) + { + SwAccessibleSelectedParas_Impl::iterator aIter = mpSelectedParas->begin(); + for ( ; aIter != mpSelectedParas->end(); ++aIter ) + { + bool bSubmitEvent( false ); + if ( !pPrevSelectedParas ) + { + // new selection + bSubmitEvent = true; + } + else + { + SwAccessibleSelectedParas_Impl::iterator aPrevSelected = + pPrevSelectedParas->find( (*aIter).first ); + if ( aPrevSelected != pPrevSelectedParas->end() ) + { + // check, if selection has changed + if ( (*aIter).second.nStartOfSelection != + (*aPrevSelected).second.nStartOfSelection || + (*aIter).second.nEndOfSelection != + (*aPrevSelected).second.nEndOfSelection ) + { + // changed selection + bSubmitEvent = true; + } + pPrevSelectedParas->erase( aPrevSelected ); + } + else + { + // new selection + bSubmitEvent = true; + } + } + + if ( bSubmitEvent ) + { + uno::Reference < XAccessible > xAcc( (*aIter).first ); + if ( xAcc.is() ) + { + ::rtl::Reference < SwAccessibleContext > xAccImpl( + static_cast<SwAccessibleContext*>( xAcc.get() ) ); + if ( xAccImpl.is() && xAccImpl->GetFrm() ) + { + const SwTxtFrm* pTxtFrm( + dynamic_cast<const SwTxtFrm*>(xAccImpl->GetFrm()) ); + OSL_ENSURE( pTxtFrm, + "<SwAccessibleMap::_SubmitTextSelectionChangedEvents()> - unexcepted type of frame" ); + if ( pTxtFrm ) + { + InvalidateParaTextSelection( *pTxtFrm ); + } + } + } + } + } + } + + // second, handle previous selections - after the first step the data + // structure of the previously known only contains the 'old' selections + if ( pPrevSelectedParas ) + { + SwAccessibleSelectedParas_Impl::iterator aIter = pPrevSelectedParas->begin(); + for ( ; aIter != pPrevSelectedParas->end(); ++aIter ) + { + uno::Reference < XAccessible > xAcc( (*aIter).first ); + if ( xAcc.is() ) + { + ::rtl::Reference < SwAccessibleContext > xAccImpl( + static_cast<SwAccessibleContext*>( xAcc.get() ) ); + if ( xAccImpl.is() && xAccImpl->GetFrm() ) + { + const SwTxtFrm* pTxtFrm( + dynamic_cast<const SwTxtFrm*>(xAccImpl->GetFrm()) ); + OSL_ENSURE( pTxtFrm, + "<SwAccessibleMap::_SubmitTextSelectionChangedEvents()> - unexcepted type of frame" ); + if ( pTxtFrm ) + { + InvalidateParaTextSelection( *pTxtFrm ); + } + } + } + } + + delete pPrevSelectedParas; + } +} + +const SwRect& SwAccessibleMap::GetVisArea() const +{ + DBG_ASSERT( !GetShell()->IsPreView() || (mpPreview != NULL), + "preview without preview data?" ); + + return GetShell()->IsPreView() + ? mpPreview->GetVisArea() + : GetShell()->VisArea(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accnotextframe.cxx b/sw/source/core/access/accnotextframe.cxx new file mode 100644 index 000000000000..6777b63f23a5 --- /dev/null +++ b/sw/source/core/access/accnotextframe.cxx @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <frmfmt.hxx> +#include <ndnotxt.hxx> +#include <flyfrm.hxx> +#include <cntfrm.hxx> +#include <hints.hxx> //#i73249# +#include "accnotextframe.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +const SwNoTxtNode *SwAccessibleNoTextFrame::GetNoTxtNode() const +{ + const SwNoTxtNode *pNd = 0; + const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm *>( GetFrm() ); + if( pFlyFrm->Lower() && pFlyFrm->Lower()->IsNoTxtFrm() ) + { + const SwCntntFrm *pCntFrm = + static_cast<const SwCntntFrm *>( pFlyFrm->Lower() ); + pNd = pCntFrm->GetNode()->GetNoTxtNode(); + } + + return pNd; +} + +SwAccessibleNoTextFrame::SwAccessibleNoTextFrame( + SwAccessibleMap* pInitMap, + sal_Int16 nInitRole, + const SwFlyFrm* pFlyFrm ) : + SwAccessibleFrameBase( pInitMap, nInitRole, pFlyFrm ), + aDepend( this, const_cast < SwNoTxtNode * >( GetNoTxtNode() ) ), + msTitle(), + msDesc() +{ + const SwNoTxtNode* pNd = GetNoTxtNode(); + // #i73249# + // consider new attributes Title and Description + if( pNd ) + { + msTitle = pNd->GetTitle(); + + msDesc = pNd->GetDescription(); + if ( msDesc.getLength() == 0 && + msTitle != GetName() ) + { + msDesc = msTitle; + } + } + // <-- +} + +SwAccessibleNoTextFrame::~SwAccessibleNoTextFrame() +{ +} + +void SwAccessibleNoTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) +{ + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; + // #i73249# + // suppress handling of RES_NAME_CHANGED in case that attribute Title is + // used as the accessible name. + if ( nWhich != RES_NAME_CHANGED || + msTitle.getLength() == 0 ) + { + SwAccessibleFrameBase::Modify( pOld, pNew ); + } + + const SwNoTxtNode *pNd = GetNoTxtNode(); + OSL_ENSURE( pNd == aDepend.GetRegisteredIn(), "invalid frame" ); + switch( nWhich ) + { + // #i73249# + case RES_TITLE_CHANGED: + { + const String& sOldTitle( + dynamic_cast<const SwStringMsgPoolItem*>(pOld)->GetString() ); + const String& sNewTitle( + dynamic_cast<const SwStringMsgPoolItem*>(pNew)->GetString() ); + if ( sOldTitle == sNewTitle ) + { + break; + } + msTitle = sNewTitle; + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::NAME_CHANGED; + aEvent.OldValue <<= OUString( sOldTitle ); + aEvent.NewValue <<= msTitle; + FireAccessibleEvent( aEvent ); + + if ( pNd->GetDescription().Len() != 0 ) + { + break; + } + } + // intentional no break here + case RES_DESCRIPTION_CHANGED: + { + if ( pNd && GetFrm() ) + { + const OUString sOldDesc( msDesc ); + + const String& rDesc = pNd->GetDescription(); + msDesc = rDesc; + if ( msDesc.getLength() == 0 && + msTitle != GetName() ) + { + msDesc = msTitle; + } + + if ( msDesc != sOldDesc ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; + aEvent.OldValue <<= sOldDesc; + aEvent.NewValue <<= msDesc; + FireAccessibleEvent( aEvent ); + } + } + } + break; + } +} + +void SwAccessibleNoTextFrame::Dispose( sal_Bool bRecursive ) +{ + SolarMutexGuard aGuard; + + if( aDepend.GetRegisteredIn() ) + const_cast < SwModify *>( aDepend.GetRegisteredIn() )->Remove( &aDepend ); + + SwAccessibleFrameBase::Dispose( bRecursive ); +} + +// #i73249# +OUString SAL_CALL SwAccessibleNoTextFrame::getAccessibleName (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + if ( msTitle.getLength() != 0 ) + { + return msTitle; + } + + return SwAccessibleFrameBase::getAccessibleName(); +} +// <-- + +OUString SAL_CALL SwAccessibleNoTextFrame::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + return msDesc; +} + + + +// +// XInterface +// + +uno::Any SAL_CALL SwAccessibleNoTextFrame::queryInterface( const uno::Type& aType ) + throw (uno::RuntimeException) +{ + if( aType == + ::getCppuType( static_cast<uno::Reference<XAccessibleImage>*>( NULL ) ) ) + { + uno::Reference<XAccessibleImage> xImage = this; + uno::Any aAny; + aAny <<= xImage; + return aAny; + } + else + return SwAccessibleContext::queryInterface( aType ); +} + + +//====== XTypeProvider ==================================================== +uno::Sequence< uno::Type > SAL_CALL SwAccessibleNoTextFrame::getTypes() throw(uno::RuntimeException) +{ + uno::Sequence< uno::Type > aTypes( SwAccessibleFrameBase::getTypes() ); + + sal_Int32 nIndex = aTypes.getLength(); + aTypes.realloc( nIndex + 1 ); + + uno::Type* pTypes = aTypes.getArray(); + pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleImage > * >( 0 ) ); + + return aTypes; +} + + +// +// XAccessibleImage +// + +// implementation of the XAccessibleImage methods is a no-brainer, as +// all releveant information is already accessible through other +// methods. So we just delegate to those. + +OUString SAL_CALL SwAccessibleNoTextFrame::getAccessibleImageDescription() + throw ( uno::RuntimeException ) +{ + return getAccessibleDescription(); +} + +sal_Int32 SAL_CALL SwAccessibleNoTextFrame::getAccessibleImageHeight( ) + throw ( uno::RuntimeException ) +{ + return getSize().Height; +} + +sal_Int32 SAL_CALL SwAccessibleNoTextFrame::getAccessibleImageWidth( ) + throw ( uno::RuntimeException ) +{ + return getSize().Width; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accnotextframe.hxx b/sw/source/core/access/accnotextframe.hxx new file mode 100644 index 000000000000..ce4ef672c110 --- /dev/null +++ b/sw/source/core/access/accnotextframe.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCNOTEXTFRAME_HXX +#define _ACCNOTEXTFRAME_HXX +#include "accframebase.hxx" +#include <com/sun/star/accessibility/XAccessibleImage.hpp> + +class SwFlyFrm; +class SwNoTxtNode; + +class SwAccessibleNoTextFrame : public SwAccessibleFrameBase, + public ::com::sun::star::accessibility::XAccessibleImage +{ + SwDepend aDepend; + ::rtl::OUString msTitle; // #i73249# + ::rtl::OUString msDesc; + +protected: + + virtual ~SwAccessibleNoTextFrame(); + + const SwNoTxtNode *GetNoTxtNode() const; + + virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); + +public: + + SwAccessibleNoTextFrame( SwAccessibleMap* pInitMap, + sal_Int16 nInitRole, + const SwFlyFrm *pFlyFrm ); + + //===== XAccessibleContext ============================================== + + // #i73249# - Return the object's current name. + virtual ::rtl::OUString SAL_CALL + getAccessibleName (void) + throw (::com::sun::star::uno::RuntimeException); + // <-- + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + //===== XInterface ====================================================== + + // XInterface methods need to be implemented to disambiguate + // between those inherited through SwAcessibleContext and + // XAccessibleImage. + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire( ) throw () + { SwAccessibleContext::acquire(); }; + + virtual void SAL_CALL release( ) throw () + { SwAccessibleContext::release(); }; + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw(::com::sun::star::uno::RuntimeException); + + //===== XAccessibleImage ================================================ + + virtual ::rtl::OUString SAL_CALL + getAccessibleImageDescription( ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int32 SAL_CALL + getAccessibleImageHeight( ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int32 SAL_CALL + getAccessibleImageWidth( ) + throw ( ::com::sun::star::uno::RuntimeException ); + + // The object is not visible an longer and should be destroyed + virtual void Dispose( sal_Bool bRecursive = sal_False ); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accpage.cxx b/sw/source/core/access/accpage.cxx new file mode 100644 index 000000000000..2b5886e026d2 --- /dev/null +++ b/sw/source/core/access/accpage.cxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <rtl/uuid.h> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include "accpage.hxx" + +#include "access.hrc" +#include <pagefrm.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using uno::Reference; +using uno::RuntimeException; +using uno::Sequence; +using ::rtl::OUString; + + +const sal_Char sServiceName[] = "com.sun.star.text.AccessiblePageView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessiblePageView"; + +sal_Bool SwAccessiblePage::IsSelected() +{ + return GetMap()->IsPageSelected( static_cast < const SwPageFrm * >( GetFrm() ) ); +} + +void SwAccessiblePage::GetStates( + ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SwAccessibleContext::GetStates( rStateSet ); + + // FOCUSABLE + rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + + // FOCUSED + if( IsSelected() ) + { + OSL_ENSURE( bIsSelected, "bSelected out of sync" ); + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() ) + rStateSet.AddState( AccessibleStateType::FOCUSED ); + } +} + +void SwAccessiblePage::_InvalidateCursorPos() +{ + sal_Bool bNewSelected = IsSelected(); + sal_Bool bOldSelected; + + { + osl::MutexGuard aGuard( aMutex ); + bOldSelected = bIsSelected; + bIsSelected = bNewSelected; + } + + if( bNewSelected ) + { + // remember that object as the one that has the caret. This is + // neccessary to notify that object if the cursor leaves it. + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } + + if( bOldSelected != bNewSelected ) + { + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() ) + FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected ); + } +} + +void SwAccessiblePage::_InvalidateFocus() +{ + Window *pWin = GetWindow(); + if( pWin ) + { + sal_Bool bSelected; + + { + osl::MutexGuard aGuard( aMutex ); + bSelected = bIsSelected; + } + OSL_ENSURE( bSelected, "focus object should be selected" ); + + FireStateChangedEvent( AccessibleStateType::FOCUSED, + pWin->HasFocus() && bSelected ); + } +} + +SwAccessiblePage::SwAccessiblePage( SwAccessibleMap* pInitMap, + const SwFrm* pFrame ) + : SwAccessibleContext( pInitMap, AccessibleRole::PANEL, pFrame ) + , bIsSelected( sal_False ) +{ + DBG_ASSERT( pFrame != NULL, "need frame" ); + DBG_ASSERT( pInitMap != NULL, "need map" ); + DBG_ASSERT( pFrame->IsPageFrm(), "need page frame" ); + + SolarMutexGuard aGuard; + + OUString sPage = OUString::valueOf( + static_cast<sal_Int32>( + static_cast<const SwPageFrm*>( GetFrm() )->GetPhyPageNum() ) ); + SetName( GetResource( STR_ACCESS_PAGE_NAME, &sPage ) ); +} + +SwAccessiblePage::~SwAccessiblePage() +{ +} + +sal_Bool SwAccessiblePage::HasCursor() +{ + osl::MutexGuard aGuard( aMutex ); + return bIsSelected; +} + +OUString SwAccessiblePage::getImplementationName( ) + throw( RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SwAccessiblePage::supportsService( const OUString& rServiceName) + throw( RuntimeException ) +{ + return rServiceName.equalsAsciiL( sServiceName, sizeof(sServiceName)-1 ) || + rServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +Sequence<OUString> SwAccessiblePage::getSupportedServiceNames( ) + throw( RuntimeException ) +{ + Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +Sequence< sal_Int8 > SAL_CALL SwAccessiblePage::getImplementationId() + throw(RuntimeException) +{ + SolarMutexGuard aGuard; + static Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +OUString SwAccessiblePage::getAccessibleDescription( ) + throw( RuntimeException ) +{ + CHECK_FOR_DEFUNC( ::com::sun::star::accessibility::XAccessibleContext ); + + OUString sArg( GetFormattedPageNumber() ); + return GetResource( STR_ACCESS_PAGE_DESC, &sArg ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accpage.hxx b/sw/source/core/access/accpage.hxx new file mode 100644 index 000000000000..ebb96cf8948f --- /dev/null +++ b/sw/source/core/access/accpage.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCPAGE_HXX +#define _ACCPAGE_HXX + +#include "acccontext.hxx" + + +/** + * accessibility implementation for the page (SwPageFrm) + * The page is _only_ visible in the page preview. For the regular + * document view, it doesn't make sense to add this additional element + * into the hierarchy. For the page preview, however, the page is the + * important. + */ +class SwAccessiblePage : public SwAccessibleContext +{ + sal_Bool bIsSelected; // protected by base class mutex + + sal_Bool IsSelected(); + + using SwAccessibleFrame::GetBounds; + +protected: + + // return the bounding box for the page in page preview mode + SwRect GetBounds( /* const SwFrm *pFrm =0 */ ); + + // Set states for getAccessibleStateSet. + // This drived class additionaly sets + // FOCUSABLE(1) and FOCUSED(+) + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + virtual void _InvalidateCursorPos(); + virtual void _InvalidateFocus(); + + virtual ~SwAccessiblePage(); + +public: + // convenience constructor to avoid typecast; + // may only be called with SwPageFrm argument + SwAccessiblePage( SwAccessibleMap* pInitMap, const SwFrm* pFrame ); + + + + // + // XAccessibleContext methods that need to be overridden + // + + virtual ::rtl::OUString SAL_CALL getAccessibleDescription (void) + throw (::com::sun::star::uno::RuntimeException); + + // + // XServiceInfo + // + + virtual ::rtl::OUString SAL_CALL getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService ( + const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + virtual sal_Bool HasCursor(); // required by map to remember that object +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx new file mode 100644 index 000000000000..f515494d234d --- /dev/null +++ b/sw/source/core/access/accpara.cxx @@ -0,0 +1,2611 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <txtfrm.hxx> +#include <flyfrm.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <unotextrange.hxx> +#include <unocrsrhelper.hxx> +#include <crstate.hxx> +#include <accmap.hxx> +#include <fesh.hxx> +#include <viewopt.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <breakit.hxx> +#include <accpara.hxx> +#include <access.hrc> +#include <accportions.hxx> +#include <sfx2/viewsh.hxx> // for ExecuteAtViewShell(...) +#include <sfx2/viewfrm.hxx> // for ExecuteAtViewShell(...) +#include <sfx2/dispatch.hxx> // for ExecuteAtViewShell(...) +#include <unotools/charclass.hxx> // for GetWordBoundary +// for get/setCharacterAttribute(...) +#include <unocrsr.hxx> +#include <unoport.hxx> +#include <doc.hxx> +#include <crsskip.hxx> +#include <txtatr.hxx> +#include <acchyperlink.hxx> +#include <acchypertextdata.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <comphelper/accessibletexthelper.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> +#include <com/sun/star/text/WritingMode2.hpp> +#include <editeng/brshitem.hxx> +#include <viewimp.hxx> +#include <boost/scoped_ptr.hpp> +#include <textmarkuphelper.hxx> +// #i10825# +#include <parachangetrackinginfo.hxx> +#include <com/sun/star/text/TextMarkupType.hpp> +// <-- +#include <comphelper/stlunosequence.hxx> // #i92233# + +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using beans::PropertyValue; +using beans::XMultiPropertySet; +using beans::UnknownPropertyException; +using beans::PropertyState_DIRECT_VALUE; + +using std::max; +using std::min; +using std::sort; + +namespace com { namespace sun { namespace star { + namespace text { + class XText; + } +} } } + + +const sal_Char sServiceName[] = "com.sun.star.text.AccessibleParagraphView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView"; +const xub_StrLen MAX_DESC_TEXT_LEN = 40; +const SwTxtNode* SwAccessibleParagraph::GetTxtNode() const +{ + const SwFrm* pFrm = GetFrm(); + DBG_ASSERT( pFrm->IsTxtFrm(), "The text frame has mutated!" ); + + const SwTxtNode* pNode = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode(); + DBG_ASSERT( pNode != NULL, "A text frame without a text node." ); + + return pNode; +} + +::rtl::OUString SwAccessibleParagraph::GetString() +{ + return GetPortionData().GetAccessibleString(); +} + +::rtl::OUString SwAccessibleParagraph::GetDescription() +{ + return ::rtl::OUString(); // provide empty description for paragraphs +} + +sal_Int32 SwAccessibleParagraph::GetCaretPos() +{ + sal_Int32 nRet = -1; + + // get the selection's point, and test whether it's in our node + // #i27301# - consider adjusted method signature + SwPaM* pCaret = GetCursor( false ); // caret is first PaM in PaM-ring + + if( pCaret != NULL ) + { + const SwTxtNode* pNode = GetTxtNode(); + + // check whether the point points into 'our' node + SwPosition* pPoint = pCaret->GetPoint(); + if( pNode->GetIndex() == pPoint->nNode.GetIndex() ) + { + // same node? Then check whether it's also within 'our' part + // of the paragraph + sal_uInt16 nIndex = pPoint->nContent.GetIndex(); + if( GetPortionData().IsValidCorePosition( nIndex ) ) + { + // Yes, it's us! + // consider that cursor/caret is in front of the list label + if ( pCaret->IsInFrontOfLabel() ) + { + nRet = 0; + } + else + { + nRet = GetPortionData().GetAccessiblePosition( nIndex ); + } + + DBG_ASSERT( nRet >= 0, "invalid cursor?" ); + DBG_ASSERT( nRet <= GetPortionData().GetAccessibleString(). + getLength(), "invalid cursor?" ); + } + // else: in this paragraph, but in different frame + } + // else: not in this paragraph + } + // else: no cursor -> no caret + + return nRet; +} + +sal_Bool SwAccessibleParagraph::GetSelection( + sal_Int32& nStart, sal_Int32& nEnd) +{ + sal_Bool bRet = sal_False; + nStart = -1; + nEnd = -1; + + // get the selection, and test whether it affects our text node + SwPaM* pCrsr = GetCursor( true ); // #i27301# - consider adjusted method signature + if( pCrsr != NULL ) + { + // get SwPosition for my node + const SwTxtNode* pNode = GetTxtNode(); + sal_uLong nHere = pNode->GetIndex(); + + // iterate over ring + SwPaM* pRingStart = pCrsr; + do + { + // ignore, if no mark + if( pCrsr->HasMark() ) + { + // check whether nHere is 'inside' pCrsr + SwPosition* pStart = pCrsr->Start(); + sal_uLong nStartIndex = pStart->nNode.GetIndex(); + SwPosition* pEnd = pCrsr->End(); + sal_uLong nEndIndex = pEnd->nNode.GetIndex(); + if( ( nHere >= nStartIndex ) && + ( nHere <= nEndIndex ) ) + { + // translate start and end positions + + // start position + sal_Int32 nLocalStart = -1; + if( nHere > nStartIndex ) + { + // selection starts in previous node: + // then our local selection starts with the paragraph + nLocalStart = 0; + } + else + { + DBG_ASSERT( nHere == nStartIndex, + "miscalculated index" ); + + // selection starts in this node: + // then check whether it's before or inside our part of + // the paragraph, and if so, get the proper position + sal_uInt16 nCoreStart = pStart->nContent.GetIndex(); + if( nCoreStart < + GetPortionData().GetFirstValidCorePosition() ) + { + nLocalStart = 0; + } + else if( nCoreStart <= + GetPortionData().GetLastValidCorePosition() ) + { + DBG_ASSERT( + GetPortionData().IsValidCorePosition( + nCoreStart ), + "problem determining valid core position" ); + + nLocalStart = + GetPortionData().GetAccessiblePosition( + nCoreStart ); + } + } + + // end position + sal_Int32 nLocalEnd = -1; + if( nHere < nEndIndex ) + { + // selection ends in following node: + // then our local selection extends to the end + nLocalEnd = GetPortionData().GetAccessibleString(). + getLength(); + } + else + { + DBG_ASSERT( nHere == nEndIndex, + "miscalculated index" ); + + // selection ends in this node: then select everything + // before our part of the node + sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex(); + if( nCoreEnd > + GetPortionData().GetLastValidCorePosition() ) + { + // selection extends beyond out part of this para + nLocalEnd = GetPortionData().GetAccessibleString(). + getLength(); + } + else if( nCoreEnd >= + GetPortionData().GetFirstValidCorePosition() ) + { + // selection is inside our part of this para + DBG_ASSERT( + GetPortionData().IsValidCorePosition( + nCoreEnd ), + "problem determining valid core position" ); + + nLocalEnd = GetPortionData().GetAccessiblePosition( + nCoreEnd ); + } + } + + if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) ) + { + nStart = nLocalStart; + nEnd = nLocalEnd; + bRet = sal_True; + } + } + // else: this PaM doesn't point to this paragraph + } + // else: this PaM is collapsed and doesn't select anything + + // next PaM in ring + pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() ); + } + while( !bRet && (pCrsr != pRingStart) ); + } + // else: nocursor -> no selection + + return bRet; +} + +// #i27301# - new parameter <_bForSelection> +SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection ) +{ + // get the cursor shell; if we don't have any, we don't have a + // cursor/selection either + SwPaM* pCrsr = NULL; + SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell(); + // #i27301# - if cursor is retrieved for selection, the cursors for + // a table selection has to be returned. + if ( pCrsrShell != NULL && + ( _bForSelection || !pCrsrShell->IsTableMode() ) ) + // <-- + { + SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell ) + ? static_cast< SwFEShell * >( pCrsrShell ) : 0; + if( !pFESh || + !(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) ) + { + // get the selection, and test whether it affects our text node + pCrsr = pCrsrShell->GetCrsr( sal_False /* ??? */ ); + } + } + + return pCrsr; +} + +sal_Bool SwAccessibleParagraph::IsHeading() const +{ + const SwTxtNode *pTxtNd = GetTxtNode(); + return pTxtNd->IsOutline(); +} + +void SwAccessibleParagraph::GetStates( + ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SwAccessibleContext::GetStates( rStateSet ); + + // MULTILINE + rStateSet.AddState( AccessibleStateType::MULTI_LINE ); + + // MULTISELECTABLE + SwCrsrShell *pCrsrSh = GetCrsrShell(); + if( pCrsrSh ) + rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE ); + + // FOCUSABLE + if( pCrsrSh ) + rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + + // FOCUSED (simulates node index of cursor) + SwPaM* pCaret = GetCursor( false ); // #i27301# - consider adjusted method signature + const SwTxtNode* pTxtNd = GetTxtNode(); + if( pCaret != 0 && pTxtNd != 0 && + pTxtNd->GetIndex() == pCaret->GetPoint()->nNode.GetIndex() && + nOldCaretPos != -1) + { + Window *pWin = GetWindow(); + if( pWin && pWin->HasFocus() ) + rStateSet.AddState( AccessibleStateType::FOCUSED ); + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } +} + +void SwAccessibleParagraph::_InvalidateContent( sal_Bool bVisibleDataFired ) +{ + ::rtl::OUString sOldText( GetString() ); + + ClearPortionData(); + + const ::rtl::OUString& rText = GetString(); + + if( rText != sOldText ) + { + // The text is changed + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TEXT_CHANGED; + + // determine exact changes between sOldText and rText + comphelper::OCommonAccessibleText::implInitTextChangedEvent( + sOldText, rText, + aEvent.OldValue, aEvent.NewValue ); + + FireAccessibleEvent( aEvent ); + } + else if( !bVisibleDataFired ) + { + FireVisibleDataEvent(); + } + + sal_Bool bNewIsHeading = IsHeading(); + sal_Bool bOldIsHeading; + { + osl::MutexGuard aGuard( aMutex ); + bOldIsHeading = bIsHeading; + if( bIsHeading != bNewIsHeading ) + bIsHeading = bNewIsHeading; + } + + + if( bNewIsHeading != bOldIsHeading || rText != sOldText ) + { + ::rtl::OUString sNewDesc( GetDescription() ); + ::rtl::OUString sOldDesc; + { + osl::MutexGuard aGuard( aMutex ); + sOldDesc = sDesc; + if( sDesc != sNewDesc ) + sDesc = sNewDesc; + } + + if( sNewDesc != sOldDesc ) + { + // The text is changed + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; + aEvent.OldValue <<= sOldDesc; + aEvent.NewValue <<= sNewDesc; + + FireAccessibleEvent( aEvent ); + } + } +} + +void SwAccessibleParagraph::_InvalidateCursorPos() +{ + // The text is changed + sal_Int32 nNew = GetCaretPos(); + sal_Int32 nOld; + { + osl::MutexGuard aGuard( aMutex ); + nOld = nOldCaretPos; + nOldCaretPos = nNew; + } + if( -1 != nNew ) + { + // remember that object as the one that has the caret. This is + // neccessary to notify that object if the cursor leaves it. + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } + + Window *pWin = GetWindow(); + if( nOld != nNew ) + { + // The cursor's node position is sumilated by the focus! + if( pWin && pWin->HasFocus() && -1 == nOld ) + FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True ); + + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CARET_CHANGED; + aEvent.OldValue <<= nOld; + aEvent.NewValue <<= nNew; + + FireAccessibleEvent( aEvent ); + + if( pWin && pWin->HasFocus() && -1 == nNew ) + FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_False ); + } +} + +void SwAccessibleParagraph::_InvalidateFocus() +{ + Window *pWin = GetWindow(); + if( pWin ) + { + sal_Int32 nPos; + { + osl::MutexGuard aGuard( aMutex ); + nPos = nOldCaretPos; + } + OSL_ENSURE( nPos != -1, "focus object should be selected" ); + + FireStateChangedEvent( AccessibleStateType::FOCUSED, + pWin->HasFocus() && nPos != -1 ); + } +} + +SwAccessibleParagraph::SwAccessibleParagraph( + SwAccessibleMap& rInitMap, + const SwTxtFrm& rTxtFrm ) + : SwClient( const_cast<SwTxtNode*>(rTxtFrm.GetTxtNode()) ) // #i108125# + , SwAccessibleContext( &rInitMap, AccessibleRole::PARAGRAPH, &rTxtFrm ) + , sDesc() + , pPortionData( NULL ) + , pHyperTextData( NULL ) + , nOldCaretPos( -1 ) + , bIsHeading( sal_False ) + , aSelectionHelper( *this ) + , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTxtFrm ) ) // #i108125# +{ + SolarMutexGuard aGuard; + + bIsHeading = IsHeading(); + SetName( ::rtl::OUString() ); // set an empty accessibility name for paragraphs + + // If this object has the focus, then it is remembered by the map itself. + nOldCaretPos = GetCaretPos(); +} + +SwAccessibleParagraph::~SwAccessibleParagraph() +{ + SolarMutexGuard aGuard; + + delete pPortionData; + delete pHyperTextData; + delete mpParaChangeTrackInfo; // #i108125# +} + +sal_Bool SwAccessibleParagraph::HasCursor() +{ + osl::MutexGuard aGuard( aMutex ); + return nOldCaretPos != -1; +} + +void SwAccessibleParagraph::UpdatePortionData() + throw( uno::RuntimeException ) +{ + // obtain the text frame + DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" ); + DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" ); + const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() ); + + // build new portion data + delete pPortionData; + pPortionData = new SwAccessiblePortionData( + pFrm->GetTxtNode(), GetMap()->GetShell()->GetViewOptions() ); + pFrm->VisitPortions( *pPortionData ); + + DBG_ASSERT( pPortionData != NULL, "UpdatePortionData() failed" ); +} + +void SwAccessibleParagraph::ClearPortionData() +{ + delete pPortionData; + pPortionData = NULL; + + delete pHyperTextData; + pHyperTextData = 0; +} + + +void SwAccessibleParagraph::ExecuteAtViewShell( sal_uInt16 nSlot ) +{ + DBG_ASSERT( GetMap() != NULL, "no map?" ); + ViewShell* pViewShell = GetMap()->GetShell(); + + DBG_ASSERT( pViewShell != NULL, "View shell exptected!" ); + SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell(); + + DBG_ASSERT( pSfxShell != NULL, "SfxViewShell shell exptected!" ); + if( !pSfxShell ) + return; + + SfxViewFrame *pFrame = pSfxShell->GetViewFrame(); + DBG_ASSERT( pFrame != NULL, "View frame exptected!" ); + if( !pFrame ) + return; + + SfxDispatcher *pDispatcher = pFrame->GetDispatcher(); + DBG_ASSERT( pDispatcher != NULL, "Dispatcher exptected!" ); + if( !pDispatcher ) + return; + + pDispatcher->Execute( nSlot ); +} + +SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion( + sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) +{ + DBG_ASSERT( (IsValidChar(nStartIndex, GetString().getLength()) && + (nEndIndex == -1)) || + IsValidRange(nStartIndex, nEndIndex, GetString().getLength()), + "please check parameters before calling this method" ); + + sal_uInt16 nStart = GetPortionData().GetModelPosition( nStartIndex ); + sal_uInt16 nEnd = (nEndIndex == -1) ? (nStart + 1) : + GetPortionData().GetModelPosition( nEndIndex ); + + // create UNO cursor + SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() ); + SwIndex aIndex( pTxtNode, nStart ); + SwPosition aStartPos( *pTxtNode, aIndex ); + SwUnoCrsr* pUnoCursor = pTxtNode->GetDoc()->CreateUnoCrsr( aStartPos ); + pUnoCursor->SetMark(); + pUnoCursor->GetMark()->nContent = nEnd; + + // create a (dummy) text portion to be returned + uno::Reference<text::XText> aEmpty; + SwXTextPortion* pPortion = + new SwXTextPortion ( pUnoCursor, aEmpty, PORTION_TEXT); + delete pUnoCursor; + + return pPortion; +} + + +// +// range checking for parameter +// + +sal_Bool SwAccessibleParagraph::IsValidChar( + sal_Int32 nPos, sal_Int32 nLength) +{ + return (nPos >= 0) && (nPos < nLength); +} + +sal_Bool SwAccessibleParagraph::IsValidPosition( + sal_Int32 nPos, sal_Int32 nLength) +{ + return (nPos >= 0) && (nPos <= nLength); +} + +sal_Bool SwAccessibleParagraph::IsValidRange( + sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength) +{ + return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength); +} + + +// +// text boundaries +// + + +sal_Bool SwAccessibleParagraph::GetCharBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString&, + sal_Int32 nPos ) +{ + rBound.startPos = nPos; + rBound.endPos = nPos+1; + return sal_True; +} + +sal_Bool SwAccessibleParagraph::GetWordBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString& rText, + sal_Int32 nPos ) +{ + sal_Bool bRet = sal_False; + + // now ask the Break-Iterator for the word + DBG_ASSERT( pBreakIt != NULL, "We always need a break." ); + DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." ); + if( pBreakIt->GetBreakIter().is() ) + { + // get locale for this position + sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos ); + lang::Locale aLocale = pBreakIt->GetLocale( + GetTxtNode()->GetLang( nModelPos ) ); + + // which type of word are we interested in? + // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.) + const sal_uInt16 nWordType = i18n::WordType::ANY_WORD; + + // get word boundary, as the Break-Iterator sees fit. + rBound = pBreakIt->GetBreakIter()->getWordBoundary( + rText, nPos, aLocale, nWordType, sal_True ); + + // It's a word if the first character is an alpha-numeric character. + bRet = GetAppCharClass().isLetterNumeric( + rText.getStr()[ rBound.startPos ] ); + } + else + { + // no break Iterator -> no word + rBound.startPos = nPos; + rBound.endPos = nPos; + } + + return bRet; +} + +sal_Bool SwAccessibleParagraph::GetSentenceBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString&, + sal_Int32 nPos ) +{ + GetPortionData().GetSentenceBoundary( rBound, nPos ); + return sal_True; +} + +sal_Bool SwAccessibleParagraph::GetLineBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString& rText, + sal_Int32 nPos ) +{ + if( rText.getLength() == nPos ) + GetPortionData().GetLastLineBoundary( rBound ); + else + GetPortionData().GetLineBoundary( rBound, nPos ); + return sal_True; +} + +sal_Bool SwAccessibleParagraph::GetParagraphBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString& rText, + sal_Int32 ) +{ + rBound.startPos = 0; + rBound.endPos = rText.getLength(); + return sal_True; +} + +sal_Bool SwAccessibleParagraph::GetAttributeBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString&, + sal_Int32 nPos ) +{ + GetPortionData().GetAttributeBoundary( rBound, nPos ); + return sal_True; +} + +sal_Bool SwAccessibleParagraph::GetGlyphBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString& rText, + sal_Int32 nPos ) +{ + sal_Bool bRet = sal_False; + + // ask the Break-Iterator for the glyph by moving one cell + // forward, and then one cell back + DBG_ASSERT( pBreakIt != NULL, "We always need a break." ); + DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." ); + if( pBreakIt->GetBreakIter().is() ) + { + // get locale for this position + sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos ); + lang::Locale aLocale = pBreakIt->GetLocale( + GetTxtNode()->GetLang( nModelPos ) ); + + // get word boundary, as the Break-Iterator sees fit. + const sal_uInt16 nIterMode = i18n::CharacterIteratorMode::SKIPCELL; + sal_Int32 nDone = 0; + rBound.endPos = pBreakIt->GetBreakIter()->nextCharacters( + rText, nPos, aLocale, nIterMode, 1, nDone ); + rBound.startPos = pBreakIt->GetBreakIter()->previousCharacters( + rText, rBound.endPos, aLocale, nIterMode, 1, nDone ); + + DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" ); + DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" ); + } + else + { + // no break Iterator -> no glyph + rBound.startPos = nPos; + rBound.endPos = nPos; + } + + return bRet; +} + + +sal_Bool SwAccessibleParagraph::GetTextBoundary( + i18n::Boundary& rBound, + const ::rtl::OUString& rText, + sal_Int32 nPos, + sal_Int16 nTextType ) + throw ( + lang::IndexOutOfBoundsException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + // error checking + if( !( AccessibleTextType::LINE == nTextType + ? IsValidPosition( nPos, rText.getLength() ) + : IsValidChar( nPos, rText.getLength() ) ) ) + throw lang::IndexOutOfBoundsException(); + + sal_Bool bRet; + + switch( nTextType ) + { + case AccessibleTextType::WORD: + bRet = GetWordBoundary( rBound, rText, nPos ); + break; + + case AccessibleTextType::SENTENCE: + bRet = GetSentenceBoundary( rBound, rText, nPos ); + break; + + case AccessibleTextType::PARAGRAPH: + bRet = GetParagraphBoundary( rBound, rText, nPos ); + break; + + case AccessibleTextType::CHARACTER: + bRet = GetCharBoundary( rBound, rText, nPos ); + break; + + case AccessibleTextType::LINE: + bRet = GetLineBoundary( rBound, rText, nPos ); + break; + + case AccessibleTextType::ATTRIBUTE_RUN: + bRet = GetAttributeBoundary( rBound, rText, nPos ); + break; + + case AccessibleTextType::GLYPH: + bRet = GetGlyphBoundary( rBound, rText, nPos ); + break; + + default: + throw lang::IllegalArgumentException( ); + } + + return bRet; +} + +::rtl::OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ); + + osl::MutexGuard aGuard2( aMutex ); + if( !sDesc.getLength() ) + sDesc = GetDescription(); + + return sDesc; +} + +lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void) + throw (IllegalAccessibleComponentStateException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() ); + if( !pTxtFrm ) + { + THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" ); + } + + const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode(); + lang::Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) ); + + return aLoc; +} + +/** #i27138# - paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO */ +uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet() + throw ( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleContext ); + + utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper(); + + const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm()); + OSL_ENSURE( pTxtFrm, + "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame"); + if ( pTxtFrm ) + { + const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) ); + if ( pPrevCntFrm ) + { + uno::Sequence< uno::Reference<XInterface> > aSequence(1); + aSequence[0] = GetMap()->GetContext( pPrevCntFrm ); + AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM, + aSequence ); + pHelper->AddRelation( aAccRel ); + } + + const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) ); + if ( pNextCntFrm ) + { + uno::Sequence< uno::Reference<XInterface> > aSequence(1); + aSequence[0] = GetMap()->GetContext( pNextCntFrm ); + AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO, + aSequence ); + pHelper->AddRelation( aAccRel ); + } + } + + return pHelper; +} + +void SAL_CALL SwAccessibleParagraph::grabFocus() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ); + + // get cursor shell + SwCrsrShell *pCrsrSh = GetCrsrShell(); + SwPaM *pCrsr = GetCursor( false ); // #i27301# - consider new method signature + const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); + const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode(); + + if( pCrsrSh != 0 && pTxtNd != 0 && + ( pCrsr == 0 || + pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() || + !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) ) + { + // create pam for selection + SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ), + pTxtFrm->GetOfst() ); + SwPosition aStartPos( *pTxtNd, aIndex ); + SwPaM aPaM( aStartPos ); + + // set PaM at cursor shell + Select( aPaM ); + + + } + + /* ->#i13955# */ + Window * pWindow = GetWindow(); + + if (pWindow != NULL) + pWindow->GrabFocus(); + /* <-#i13955# */ +} + +// #i71385# +bool lcl_GetBackgroundColor( Color & rColor, + const SwFrm* pFrm, + SwCrsrShell* pCrsrSh ) +{ + const SvxBrushItem* pBackgrdBrush = 0; + const Color* pSectionTOXColor = 0; + SwRect aDummyRect; + if ( pFrm && + pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) ) + { + if ( pSectionTOXColor ) + { + rColor = *pSectionTOXColor; + return true; + } + else + { + rColor = pBackgrdBrush->GetColor(); + return true; + } + } + else if ( pCrsrSh ) + { + rColor = pCrsrSh->Imp()->GetRetoucheColor(); + return true; + } + + return false; +} + +sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground() + throw (uno::RuntimeException) +{ + Color aBackgroundCol; + + if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) ) + { + if ( aBackgroundCol.IsDark() ) + { + return COL_WHITE; + } + else + { + return COL_BLACK; + } + } + + return SwAccessibleContext::getForeground(); +} + +sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground() + throw (uno::RuntimeException) +{ + Color aBackgroundCol; + + if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) ) + { + return aBackgroundCol.GetColor(); + } + + return SwAccessibleContext::getBackground(); +} +// <-- + +::rtl::OUString SAL_CALL SwAccessibleParagraph::getImplementationName() + throw( uno::RuntimeException ) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleParagraph::supportsService( + const ::rtl::OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +uno::Sequence< ::rtl::OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > aRet(2); + ::rtl::OUString* pArray = aRet.getArray(); + pArray[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +// +//===== XInterface ======================================================= +// + +uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType ) + throw (uno::RuntimeException) +{ + uno::Any aRet; + if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) ) + { + uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity + aRet <<= aAccText; + } + else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) ) + { + uno::Reference<XAccessibleEditableText> aAccEditText = this; + aRet <<= aAccEditText; + } + else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) ) + { + uno::Reference<XAccessibleSelection> aAccSel = this; + aRet <<= aAccSel; + } + else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) ) + { + uno::Reference<XAccessibleHypertext> aAccHyp = this; + aRet <<= aAccHyp; + } + // #i63870# + // add interface com::sun:star:accessibility::XAccessibleTextAttributes + else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) ) + { + uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this; + aRet <<= aAccTextAttr; + } + // <-- + // #i89175# + // add interface com::sun:star:accessibility::XAccessibleTextMarkup + else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) ) + { + uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this; + aRet <<= aAccTextMarkup; + } + // add interface com::sun:star:accessibility::XAccessibleMultiLineText + else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) ) + { + uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this; + aRet <<= aAccMultiLineText; + } + // <-- + else + { + aRet = SwAccessibleContext::queryInterface(rType); + } + + return aRet; +} + +//====== XTypeProvider ==================================================== +uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException) +{ + uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); + + sal_Int32 nIndex = aTypes.getLength(); + // #i63870# - add type accessibility::XAccessibleTextAttributes + // #i89175# - add type accessibility::XAccessibleTextMarkup and + // accessibility::XAccessibleMultiLineText + aTypes.realloc( nIndex + 6 ); + + uno::Type* pTypes = aTypes.getArray(); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) ); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) ); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) ); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) ); + pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) ); + // <-- + + return aTypes; +} + +uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId() + throw(uno::RuntimeException) +{ + SolarMutexGuard aGuard; + static uno::Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + + +// +//===== XAccesibleText =================================================== +// + +sal_Int32 SwAccessibleParagraph::getCaretPosition() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + sal_Int32 nRet = GetCaretPos(); + { + osl::MutexGuard aOldCaretPosGuard( aMutex ); + OSL_ENSURE( nRet == nOldCaretPos, "caret pos out of sync" ); + nOldCaretPos = nRet; + } + if( -1 != nRet ) + { + ::rtl::Reference < SwAccessibleContext > xThis( this ); + GetMap()->SetCursorContext( xThis ); + } + + return nRet; +} + +sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + // parameter checking + sal_Int32 nLength = GetString().getLength(); + if ( ! IsValidPosition( nIndex, nLength ) ) + { + throw lang::IndexOutOfBoundsException(); + } + + sal_Bool bRet = sal_False; + + // get cursor shell + SwCrsrShell* pCrsrShell = GetCrsrShell(); + if( pCrsrShell != NULL ) + { + // create pam for selection + SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); + SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex)); + SwPosition aStartPos( *pNode, aIndex ); + SwPaM aPaM( aStartPos ); + + // set PaM at cursor shell + bRet = Select( aPaM ); + } + + return bRet; +} + +sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + ::rtl::OUString sText( GetString() ); + + // return character (if valid) + if( IsValidChar(nIndex, sText.getLength() ) ) + { + return sText.getStr()[nIndex]; + } + else + throw lang::IndexOutOfBoundsException(); +} + +// #i63870# - re-implement method on behalf of methods +// <_getDefaultAttributesImpl(..)> and <_getRunAttributesImpl(..)> +uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes( + sal_Int32 nIndex, + const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + const ::rtl::OUString& rText = GetString(); + + if( ! IsValidChar( nIndex, rText.getLength() ) ) + throw lang::IndexOutOfBoundsException(); + + // retrieve default character attributes + tAccParaPropValMap aDefAttrSeq; + _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true ); + + // retrieved run character attributes + tAccParaPropValMap aRunAttrSeq; + _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq ); + + // merge default and run attributes + uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 i = 0; + for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin(); + aDefIter != aDefAttrSeq.end(); + ++aDefIter ) + { + tAccParaPropValMap::const_iterator aRunIter = + aRunAttrSeq.find( aDefIter->first ); + if ( aRunIter != aRunAttrSeq.end() ) + { + pValues[i] = aRunIter->second; + } + else + { + pValues[i] = aDefIter->second; + } + ++i; + } + + return aValues; +} + +// #i63870# +void SwAccessibleParagraph::_getDefaultAttributesImpl( + const uno::Sequence< ::rtl::OUString >& aRequestedAttributes, + tAccParaPropValMap& rDefAttrSeq, + const bool bOnlyCharAttrs ) +{ + // retrieve default attributes + const SwTxtNode* pTxtNode( GetTxtNode() ); + ::boost::scoped_ptr<SfxItemSet> pSet; + if ( !bOnlyCharAttrs ) + { + pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), + RES_CHRATR_BEGIN, RES_CHRATR_END - 1, + RES_PARATR_BEGIN, RES_PARATR_END - 1, + RES_FRMATR_BEGIN, RES_FRMATR_END - 1, + 0 ) ); + } + else + { + pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), + RES_CHRATR_BEGIN, RES_CHRATR_END - 1, + 0 ) ); + } + // #i82637# - From the perspective of the a11y API the default character + // attributes are the character attributes, which are set at the paragraph style + // of the paragraph. The character attributes set at the automatic paragraph + // style of the paragraph are treated as run attributes. +// pTxtNode->SwCntntNode::GetAttr( *pSet ); + // get default paragraph attributes, if needed, and merge these into <pSet> + if ( !bOnlyCharAttrs ) + { + SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), + RES_PARATR_BEGIN, RES_PARATR_END - 1, + RES_FRMATR_BEGIN, RES_FRMATR_END - 1, + 0 ); + pTxtNode->SwCntntNode::GetAttr( aParaSet ); + pSet->Put( aParaSet ); + } + // get default character attributes and merge these into <pSet> + OSL_ENSURE( pTxtNode->GetTxtColl(), + "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" ); + if ( pTxtNode->GetTxtColl() ) + { + SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), + RES_CHRATR_BEGIN, RES_CHRATR_END - 1, + 0 ); + aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() ); + pSet->Put( aCharSet ); + } + // <-- + + // build-up sequence containing the run attributes <rDefAttrSeq> + tAccParaPropValMap aDefAttrSeq; + { + const SfxItemPropertyMap* pPropMap = + aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap(); + PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries(); + PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin(); + while ( aPropIt != aPropertyEntries.end() ) + { + const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID ); + if ( pItem ) + { + uno::Any aVal; + pItem->QueryValue( aVal, aPropIt->nMemberId ); + + PropertyValue rPropVal; + rPropVal.Name = aPropIt->sName; + rPropVal.Value = aVal; + rPropVal.Handle = -1; + rPropVal.State = beans::PropertyState_DEFAULT_VALUE; + + aDefAttrSeq[rPropVal.Name] = rPropVal; + } + ++aPropIt; + } + + // #i72800# + // add property value entry for the paragraph style + if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() ) + { + const ::rtl::OUString sParaStyleName = + ::rtl::OUString::createFromAscii( + GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName ); + if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() ) + { + PropertyValue rPropVal; + rPropVal.Name = sParaStyleName; + uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) ); + rPropVal.Value = aVal; + rPropVal.Handle = -1; + rPropVal.State = beans::PropertyState_DEFAULT_VALUE; + + aDefAttrSeq[rPropVal.Name] = rPropVal; + } + } + // <-- + + // #i73371# + // resolve value text::WritingMode2::PAGE of property value entry WritingMode + if ( !bOnlyCharAttrs && GetFrm() ) + { + const ::rtl::OUString sWritingMode = + ::rtl::OUString::createFromAscii( + GetPropName( UNO_NAME_WRITING_MODE ).pName ); + tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode ); + if ( aIter != aDefAttrSeq.end() ) + { + PropertyValue rPropVal( aIter->second ); + sal_Int16 nVal = rPropVal.Value.get<sal_Int16>(); + if ( nVal == text::WritingMode2::PAGE ) + { + const SwFrm* pUpperFrm( GetFrm()->GetUpper() ); + while ( pUpperFrm ) + { + if ( pUpperFrm->GetType() & + ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) ) + { + if ( pUpperFrm->IsVertical() ) + { + nVal = text::WritingMode2::TB_RL; + } + else if ( pUpperFrm->IsRightToLeft() ) + { + nVal = text::WritingMode2::RL_TB; + } + else + { + nVal = text::WritingMode2::LR_TB; + } + rPropVal.Value <<= nVal; + aDefAttrSeq[rPropVal.Name] = rPropVal; + break; + } + + if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) ) + { + pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm(); + } + else + { + pUpperFrm = pUpperFrm->GetUpper(); + } + } + } + } + } + // <-- + } + + if ( aRequestedAttributes.getLength() == 0 ) + { + rDefAttrSeq = aDefAttrSeq; + } + else + { + const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray(); + const sal_Int32 nLength = aRequestedAttributes.getLength(); + for( sal_Int32 i = 0; i < nLength; ++i ) + { + tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] ); + if ( aIter != aDefAttrSeq.end() ) + { + rDefAttrSeq[ aIter->first ] = aIter->second; + } + } + } +} + +uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes( + const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) + throw ( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + tAccParaPropValMap aDefAttrSeq; + _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq ); + + // #i92233# + static rtl::OUString sMMToPixelRatio(RTL_CONSTASCII_USTRINGPARAM("MMToPixelRatio")); + bool bProvideMMToPixelRatio( false ); + { + if ( aRequestedAttributes.getLength() == 0 ) + { + bProvideMMToPixelRatio = true; + } + else + { + const rtl::OUString* aRequestedAttrIter = + ::std::find( ::comphelper::stl_begin( aRequestedAttributes ), + ::comphelper::stl_end( aRequestedAttributes ), + sMMToPixelRatio ); + if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) ) + { + bProvideMMToPixelRatio = true; + } + } + } + // <-- + + uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() + + ( bProvideMMToPixelRatio ? 1 : 0 ) ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 i = 0; + for ( tAccParaPropValMap::const_iterator aIter = aDefAttrSeq.begin(); + aIter != aDefAttrSeq.end(); + ++aIter ) + { + pValues[i] = aIter->second; + ++i; + } + + // #i92233# + if ( bProvideMMToPixelRatio ) + { + PropertyValue rPropVal; + rPropVal.Name = sMMToPixelRatio; + const Size a100thMMSize( 1000, 1000 ); + const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize ); + const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width(); + rPropVal.Value = uno::makeAny( fRatio ); + rPropVal.Handle = -1; + rPropVal.State = beans::PropertyState_DEFAULT_VALUE; + pValues[ aValues.getLength() - 1 ] = rPropVal; + } + // <-- + + return aValues; +} + +void SwAccessibleParagraph::_getRunAttributesImpl( + const sal_Int32 nIndex, + const uno::Sequence< ::rtl::OUString >& aRequestedAttributes, + tAccParaPropValMap& rRunAttrSeq ) +{ + // create PaM for character at position <nIndex> + SwPaM* pPaM( 0 ); + { + const SwTxtNode* pTxtNode( GetTxtNode() ); + SwPosition* pStartPos = new SwPosition( *pTxtNode ); + pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) ); + SwPosition* pEndPos = new SwPosition( *pTxtNode ); + pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) ); + + pPaM = new SwPaM( *pStartPos, *pEndPos ); + + delete pStartPos; + delete pEndPos; + } + + // retrieve character attributes for the created PaM <pPaM> + SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(), + RES_CHRATR_BEGIN, RES_CHRATR_END -1, + 0 ); + // #i82637# + // From the perspective of the a11y API the character attributes, which + // are set at the automatic paragraph style of the paragraph are treated + // as run attributes. +// SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True ); + // get character attributes from automatic paragraph style and merge these into <aSet> + { + const SwTxtNode* pTxtNode( GetTxtNode() ); + if ( pTxtNode->HasSwAttrSet() ) + { + SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(), + RES_CHRATR_BEGIN, RES_CHRATR_END -1, + 0 ); + aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False ); + aSet.Put( aAutomaticParaStyleCharAttrs ); + } + } + // get character attributes at <pPaM> and merge these into <aSet> + { + SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(), + RES_CHRATR_BEGIN, RES_CHRATR_END -1, + 0 ); + SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True); + aSet.Put( aCharAttrsAtPaM ); + } + // <-- + + // build-up sequence containing the run attributes <rRunAttrSeq> + { + tAccParaPropValMap aRunAttrSeq; + { + tAccParaPropValMap aDefAttrSeq; + uno::Sequence< ::rtl::OUString > aDummy; + _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true ); // #i82637# + + const SfxItemPropertyMap* pPropMap = + aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap(); + PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries(); + PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin(); + while ( aPropIt != aPropertyEntries.end() ) + { + const SfxPoolItem* pItem( 0 ); + // #i82637# - Found character attributes, whose value equals the value of + // the corresponding default character attributes, are excluded. + if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET ) + { + uno::Any aVal; + pItem->QueryValue( aVal, aPropIt->nMemberId ); + + PropertyValue rPropVal; + rPropVal.Name = aPropIt->sName; + rPropVal.Value = aVal; + rPropVal.Handle = -1; + rPropVal.State = PropertyState_DIRECT_VALUE; + + tAccParaPropValMap::const_iterator aDefIter = + aDefAttrSeq.find( rPropVal.Name ); + if ( aDefIter == aDefAttrSeq.end() || + rPropVal.Value != aDefIter->second.Value ) + { + aRunAttrSeq[rPropVal.Name] = rPropVal; + } + } + + ++aPropIt; + } + } + + if ( aRequestedAttributes.getLength() == 0 ) + { + rRunAttrSeq = aRunAttrSeq; + } + else + { + const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray(); + const sal_Int32 nLength = aRequestedAttributes.getLength(); + for( sal_Int32 i = 0; i < nLength; ++i ) + { + tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] ); + if ( aIter != aRunAttrSeq.end() ) + { + rRunAttrSeq[ (*aIter).first ] = (*aIter).second; + } + } + } + } + + delete pPaM; +} + +uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes( + sal_Int32 nIndex, + const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + { + const ::rtl::OUString& rText = GetString(); + if ( !IsValidChar( nIndex, rText.getLength() ) ) + { + throw lang::IndexOutOfBoundsException(); + } + } + + tAccParaPropValMap aRunAttrSeq; + _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq ); + + uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() ); + PropertyValue* pValues = aValues.getArray(); + sal_Int32 i = 0; + for ( tAccParaPropValMap::const_iterator aIter = aRunAttrSeq.begin(); + aIter != aRunAttrSeq.end(); + ++aIter ) + { + pValues[i] = aIter->second; + ++i; + } + + return aValues; +} +// <-- + +awt::Rectangle SwAccessibleParagraph::getCharacterBounds( + sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + + /* #i12332# The position after the string needs special treatment. + IsValidChar -> IsValidPosition + */ + if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) ) + throw lang::IndexOutOfBoundsException(); + + /* #i12332# */ + sal_Bool bBehindText = sal_False; + if ( nIndex == GetString().getLength() ) + bBehindText = sal_True; + + // get model position & prepare GetCharRect() arguments + SwCrsrMoveState aMoveState; + aMoveState.bRealHeight = sal_True; + aMoveState.bRealWidth = sal_True; + SwSpecialPos aSpecialPos; + SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); + + sal_uInt16 nPos = 0; + + /* #i12332# FillSpecialPos does not accept nIndex == + GetString().getLength(). In that case nPos is set to the + length of the string in the core. This way GetCharRect + returns the rectangle for a cursor at the end of the + paragraph. */ + if (bBehindText) + { + nPos = pNode->GetTxt().Len(); + } + else + nPos = GetPortionData().FillSpecialPos + (nIndex, aSpecialPos, aMoveState.pSpecialPos ); + + // call GetCharRect + SwRect aCoreRect; + SwIndex aIndex( pNode, nPos ); + SwPosition aPosition( *pNode, aIndex ); + GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState ); + + // translate core coordinates into accessibility coordinates + Window *pWin = GetWindow(); + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); + + Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() )); + SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root + + Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() ); + aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() ); + + // convert into AWT Rectangle + return awt::Rectangle( + aScreenRect.Left(), aScreenRect.Top(), + aScreenRect.GetWidth(), aScreenRect.GetHeight() ); +} + +sal_Int32 SwAccessibleParagraph::getCharacterCount() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + return GetString().getLength(); +} + +sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + // construct SwPosition (where GetCrsrOfst() will put the result into) + SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); + SwIndex aIndex( pNode, 0); + SwPosition aPos( *pNode, aIndex ); + + // construct Point (translate into layout coordinates) + Window *pWin = GetWindow(); + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); + Point aPoint( rPoint.X, rPoint.Y ); + SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root + Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() ); + aPoint.X() += aPixPos.X(); + aPoint.Y() += aPixPos.Y(); + MapMode aMapMode = pWin->GetMapMode(); + Point aCorePoint( GetMap()->PixelToCore( aPoint ) ); + if( !aLogBounds.IsInside( aCorePoint ) ) + { + /* #i12332# rPoint is may also be in rectangle returned by + getCharacterBounds(getCharacterCount() */ + + awt::Rectangle aRectEndPos = + getCharacterBounds(getCharacterCount()); + + if (rPoint.X - aRectEndPos.X >= 0 && + rPoint.X - aRectEndPos.X < aRectEndPos.Width && + rPoint.Y - aRectEndPos.Y >= 0 && + rPoint.Y - aRectEndPos.Y < aRectEndPos.Height) + return getCharacterCount(); + + return -1; + } + + // ask core for position + DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" ); + DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" ); + const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() ); + SwCrsrMoveState aMoveState; + aMoveState.bPosMatchesBounds = sal_True; + sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState ); + + SwIndex aCntntIdx = aPos.nContent; + const xub_StrLen nIndex = aCntntIdx.GetIndex(); + if ( nIndex > 0 ) + { + SwRect aResultRect; + pFrm->GetCharRect( aResultRect, aPos ); + bool bVert = pFrm->IsVertical(); + bool bR2L = pFrm->IsRightToLeft(); + + if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) || + ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) || + ( bR2L && aResultRect.Right() < aCorePoint.X()) ) + { + SwIndex aIdxPrev( pNode, nIndex - 1); + SwPosition aPosPrev( *pNode, aIdxPrev ); + SwRect aResultRectPrev; + pFrm->GetCharRect( aResultRectPrev, aPosPrev ); + if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) || + ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) || + ( bR2L && aResultRectPrev.Right() > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ) + aPos = aPosPrev; + } + } + + return bSuccess ? + GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() ) + : -1L; +} + +::rtl::OUString SwAccessibleParagraph::getSelectedText() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + sal_Int32 nStart, nEnd; + sal_Bool bSelected = GetSelection( nStart, nEnd ); + return bSelected + ? GetString().copy( nStart, nEnd - nStart ) + : ::rtl::OUString(); +} + +sal_Int32 SwAccessibleParagraph::getSelectionStart() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + sal_Int32 nStart, nEnd; + GetSelection( nStart, nEnd ); + return nStart; +} + +sal_Int32 SwAccessibleParagraph::getSelectionEnd() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + sal_Int32 nStart, nEnd; + GetSelection( nStart, nEnd ); + return nEnd; +} + +sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + // parameter checking + sal_Int32 nLength = GetString().getLength(); + if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) ) + { + throw lang::IndexOutOfBoundsException(); + } + + sal_Bool bRet = sal_False; + + // get cursor shell + SwCrsrShell* pCrsrShell = GetCrsrShell(); + if( pCrsrShell != NULL ) + { + // create pam for selection + SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); + SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex)); + SwPosition aStartPos( *pNode, aIndex ); + SwPaM aPaM( aStartPos ); + aPaM.SetMark(); + aPaM.GetPoint()->nContent = + GetPortionData().GetModelPosition(nEndIndex); + + // set PaM at cursor shell + bRet = Select( aPaM ); + } + + return bRet; +} + +::rtl::OUString SwAccessibleParagraph::getText() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + return GetString(); +} + +::rtl::OUString SwAccessibleParagraph::getTextRange( + sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + ::rtl::OUString sText( GetString() ); + + if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) ) + { + OrderRange( nStartIndex, nEndIndex ); + return sText.copy(nStartIndex, nEndIndex-nStartIndex ); + } + else + throw lang::IndexOutOfBoundsException(); +} + +/*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + /*accessibility::*/TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + const ::rtl::OUString rText = GetString(); + // implement the silly specification that first position after + // text must return an empty string, rather than throwing an + // IndexOutOfBoundsException, except for LINE, where the last + // line is returned + if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType ) + return aResult; + + // with error checking + i18n::Boundary aBound; + sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); + + DBG_ASSERT( aBound.startPos >= 0, "illegal boundary" ); + DBG_ASSERT( aBound.startPos <= aBound.endPos, "illegal boundary" ); + + // return word (if present) + if ( bWord ) + { + aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); + aResult.SegmentStart = aBound.startPos; + aResult.SegmentEnd = aBound.endPos; + } + + return aResult; +} + +/*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + const ::rtl::OUString rText = GetString(); + + /*accessibility::*/TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + // get starting pos + i18n::Boundary aBound; + if (nIndex == rText.getLength()) + aBound.startPos = aBound.endPos = nIndex; + else + { + sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType ); + + if ( ! bTmp ) + aBound.startPos = aBound.endPos = nIndex; + } + + // now skip to previous word + sal_Bool bWord = sal_False; + while( !bWord ) + { + nIndex = min( nIndex, aBound.startPos ) - 1; + if( nIndex >= 0 ) + bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); + else + break; // exit if beginning of string is reached + } + + if ( bWord ) + { + aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); + aResult.SegmentStart = aBound.startPos; + aResult.SegmentEnd = aBound.endPos; + }; + return aResult; +} + +/*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + + /*accessibility::*/TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + const ::rtl::OUString rText = GetString(); + + // implement the silly specification that first position after + // text must return an empty string, rather than throwing an + // IndexOutOfBoundsException + if( nIndex == rText.getLength() ) + return aResult; + + + // get first word, then skip to next word + i18n::Boundary aBound; + GetTextBoundary( aBound, rText, nIndex, nTextType ); + sal_Bool bWord = sal_False; + while( !bWord ) + { + nIndex = max( sal_Int32(nIndex+1), aBound.endPos ); + if( nIndex < rText.getLength() ) + bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); + else + break; // exit if end of string is reached + } + + if ( bWord ) + { + aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); + aResult.SegmentStart = aBound.startPos; + aResult.SegmentEnd = aBound.endPos; + } + return aResult; +} + +sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); + SolarMutexGuard aGuard; + + // select and copy (through dispatch mechanism) + setSelection( nStartIndex, nEndIndex ); + ExecuteAtViewShell( SID_COPY ); + return sal_True; +} + + +// +//===== XAccesibleEditableText ========================================== +// + +sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + CHECK_FOR_DEFUNC( XAccessibleEditableText ); + SolarMutexGuard aGuard; + + if( !IsEditableState() ) + return sal_False; + + // select and cut (through dispatch mechanism) + setSelection( nStartIndex, nEndIndex ); + ExecuteAtViewShell( SID_CUT ); + return sal_True; +} + +sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + CHECK_FOR_DEFUNC( XAccessibleEditableText ); + SolarMutexGuard aGuard; + + if( !IsEditableState() ) + return sal_False; + + // select and paste (through dispatch mechanism) + setSelection( nIndex, nIndex ); + ExecuteAtViewShell( SID_PASTE ); + return sal_True; +} + +sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() ); +} + +sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + return replaceText( nIndex, nIndex, sText ); +} + +sal_Bool SwAccessibleParagraph::replaceText( + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const ::rtl::OUString& sReplacement ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleEditableText ); + + const ::rtl::OUString& rText = GetString(); + + if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) + { + if( !IsEditableState() ) + return sal_False; + + SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); + + // translate positions + sal_uInt16 nStart, nEnd; + sal_Bool bSuccess = GetPortionData().GetEditableRange( + nStartIndex, nEndIndex, nStart, nEnd ); + + // edit only if the range is editable + if( bSuccess ) + { + // create SwPosition for nStartIndex + SwIndex aIndex( pNode, nStart ); + SwPosition aStartPos( *pNode, aIndex ); + + // create SwPosition for nEndIndex + SwPosition aEndPos( aStartPos ); + aEndPos.nContent = nEnd; + + // now create XTextRange as helper and set string + const uno::Reference<text::XTextRange> xRange( + SwXTextRange::CreateXTextRange( + *pNode->GetDoc(), aStartPos, &aEndPos)); + xRange->setString(sReplacement); + + // delete portion data + ClearPortionData(); + } + + return bSuccess; + } + else + throw lang::IndexOutOfBoundsException(); +} + +struct IndexCompare +{ + const PropertyValue* pValues; + IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {} + bool operator() ( const sal_Int32& a, const sal_Int32& b ) const + { + return (pValues[a].Name < pValues[b].Name) ? true : false; + } +}; + + +sal_Bool SwAccessibleParagraph::setAttributes( + sal_Int32 nStartIndex, + sal_Int32 nEndIndex, + const uno::Sequence<PropertyValue>& rAttributeSet ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleEditableText ); + + const ::rtl::OUString& rText = GetString(); + + if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) + throw lang::IndexOutOfBoundsException(); + + if( !IsEditableState() ) + return sal_False; + + + // create a (dummy) text portion for the sole purpose of calling + // setPropertyValue on it + uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex, + nEndIndex ); + + // build sorted index array + sal_Int32 nLength = rAttributeSet.getLength(); + const PropertyValue* pPairs = rAttributeSet.getConstArray(); + sal_Int32* pIndices = new sal_Int32[nLength]; + sal_Int32 i; + for( i = 0; i < nLength; i++ ) + pIndices[i] = i; + sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) ); + + // create sorted sequences accoring to index array + uno::Sequence< ::rtl::OUString > aNames( nLength ); + ::rtl::OUString* pNames = aNames.getArray(); + uno::Sequence< uno::Any > aValues( nLength ); + uno::Any* pValues = aValues.getArray(); + for( i = 0; i < nLength; i++ ) + { + const PropertyValue& rVal = pPairs[pIndices[i]]; + pNames[i] = rVal.Name; + pValues[i] = rVal.Value; + } + delete[] pIndices; + + // now set the values + sal_Bool bRet = sal_True; + try + { + xPortion->setPropertyValues( aNames, aValues ); + } + catch( UnknownPropertyException &e ) + { + // error handling through return code! + bRet = sal_False; + } + + return bRet; +} + +sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText ) + throw (uno::RuntimeException) +{ + return replaceText(0, GetString().getLength(), sText); +} + +//===== XAccessibleSelection ============================================ + +void SwAccessibleParagraph::selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + aSelectionHelper.selectAccessibleChild(nChildIndex); +} + +sal_Bool SwAccessibleParagraph::isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + return aSelectionHelper.isAccessibleChildSelected(nChildIndex); +} + +void SwAccessibleParagraph::clearAccessibleSelection( ) + throw ( uno::RuntimeException ) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + aSelectionHelper.clearAccessibleSelection(); +} + +void SwAccessibleParagraph::selectAllAccessibleChildren( ) + throw ( uno::RuntimeException ) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + aSelectionHelper.selectAllAccessibleChildren(); +} + +sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount( ) + throw ( uno::RuntimeException ) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + return aSelectionHelper.getSelectedAccessibleChildCount(); +} + +uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex); +} + +// index has to be treated as global child index. +void SwAccessibleParagraph::deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + CHECK_FOR_DEFUNC( XAccessibleSelection ); + + aSelectionHelper.deselectAccessibleChild( nChildIndex ); +} + +//===== XAccessibleHypertext ============================================ + +class SwHyperlinkIter_Impl +{ + const SwpHints *pHints; + xub_StrLen nStt; + xub_StrLen nEnd; + sal_uInt16 nPos; + +public: + SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ); + const SwTxtAttr *next(); + sal_uInt16 getCurrHintPos() const { return nPos-1; } + + xub_StrLen startIdx() const { return nStt; } + xub_StrLen endIdx() const { return nEnd; } +}; + +SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) : + pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ), + nStt( pTxtFrm->GetOfst() ), + nPos( 0 ) +{ + const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow(); + nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len(); +} + +const SwTxtAttr *SwHyperlinkIter_Impl::next() +{ + const SwTxtAttr *pAttr = 0; + if( pHints ) + { + while( !pAttr && nPos < pHints->Count() ) + { + const SwTxtAttr *pHt = (*pHints)[nPos]; + if( RES_TXTATR_INETFMT == pHt->Which() ) + { + xub_StrLen nHtStt = *pHt->GetStart(); + xub_StrLen nHtEnd = *pHt->GetAnyEnd(); + if( nHtEnd > nHtStt && + ( (nHtStt >= nStt && nHtStt < nEnd) || + (nHtEnd > nStt && nHtEnd <= nEnd) ) ) + { + pAttr = pHt; + } + } + ++nPos; + } + } + + return pAttr; +}; + +sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleHypertext ); + + sal_Int32 nCount = 0; + // #i77108# - provide hyperlinks also in editable documents. +// if( !IsEditableState() ) + // <-- + { + const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); + SwHyperlinkIter_Impl aIter( pTxtFrm ); + while( aIter.next() ) + nCount++; + } + + return nCount; +} + +uno::Reference< XAccessibleHyperlink > SAL_CALL + SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleHypertext ); + + uno::Reference< XAccessibleHyperlink > xRet; + + // #i77108# + { + const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); + SwHyperlinkIter_Impl aHIter( pTxtFrm ); + while( nLinkIndex-- ) + aHIter.next(); + + const SwTxtAttr *pHt = aHIter.next(); + if( pHt ) + { + if( !pHyperTextData ) + pHyperTextData = new SwAccessibleHyperTextData; + SwAccessibleHyperTextData::iterator aIter = + pHyperTextData ->find( pHt ); + if( aIter != pHyperTextData->end() ) + { + xRet = (*aIter).second; + } + if( !xRet.is() ) + { + sal_Int32 nHStt= GetPortionData().GetAccessiblePosition( + max( aHIter.startIdx(), *pHt->GetStart() ) ); + sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition( + min( aHIter.endIdx(), *pHt->GetAnyEnd() ) ); + xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(), + this, nHStt, nHEnd ); + if( aIter != pHyperTextData->end() ) + { + (*aIter).second = xRet; + } + else + { + SwAccessibleHyperTextData::value_type aEntry( pHt, xRet ); + pHyperTextData->insert( aEntry ); + } + } + } + } + + if( !xRet.is() ) + throw lang::IndexOutOfBoundsException(); + + return xRet; +} + +sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleHypertext ); + + // parameter checking + sal_Int32 nLength = GetString().getLength(); + if ( ! IsValidPosition( nCharIndex, nLength ) ) + { + throw lang::IndexOutOfBoundsException(); + } + + sal_Int32 nRet = -1; + // #i77108# + { + const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); + SwHyperlinkIter_Impl aHIter( pTxtFrm ); + + xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex ); + sal_Int32 nPos = 0; + const SwTxtAttr *pHt = aHIter.next(); + while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) ) + { + pHt = aHIter.next(); + nPos++; + } + + if( pHt ) + nRet = nPos; + + } + + return nRet; +} + +// #i71360#, #i108125# - adjustments for change tracking text markup +sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType ) + throw (lang::IllegalArgumentException, + uno::RuntimeException) +{ + std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; + switch ( nTextMarkupType ) + { + case text::TextMarkupType::TRACK_CHANGE_INSERTION: + case text::TextMarkupType::TRACK_CHANGE_DELETION: + case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: + { + pTextMarkupHelper.reset( new SwTextMarkupHelper( + GetPortionData(), + *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); + } + break; + default: + { + pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); + } + } + + return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType ); +} + +/*accessibility::*/TextSegment SAL_CALL + SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex, + sal_Int32 nTextMarkupType ) + throw (lang::IndexOutOfBoundsException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; + switch ( nTextMarkupType ) + { + case text::TextMarkupType::TRACK_CHANGE_INSERTION: + case text::TextMarkupType::TRACK_CHANGE_DELETION: + case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: + { + pTextMarkupHelper.reset( new SwTextMarkupHelper( + GetPortionData(), + *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); + } + break; + default: + { + pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); + } + } + + return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType ); +} + +uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL + SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex, + sal_Int32 nTextMarkupType ) + throw (lang::IndexOutOfBoundsException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + // parameter checking + const sal_Int32 nLength = GetString().getLength(); + if ( ! IsValidPosition( nCharIndex, nLength ) ) + { + throw lang::IndexOutOfBoundsException(); + } + + std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; + switch ( nTextMarkupType ) + { + case text::TextMarkupType::TRACK_CHANGE_INSERTION: + case text::TextMarkupType::TRACK_CHANGE_DELETION: + case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: + { + pTextMarkupHelper.reset( new SwTextMarkupHelper( + GetPortionData(), + *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); + } + break; + default: + { + pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); + } + } + + return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType ); +} +// <-- + +// #i89175# +sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + // parameter checking + const sal_Int32 nLength = GetString().getLength(); + if ( ! IsValidPosition( nIndex, nLength ) ) + { + throw lang::IndexOutOfBoundsException(); + } + + const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex ); + return nLineNo; +} + +/*accessibility::*/TextSegment SAL_CALL + SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo ) + throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + // parameter checking + if ( nLineNo < 0 || + nLineNo >= GetPortionData().GetLineCount() ) + { + throw lang::IndexOutOfBoundsException(); + } + + i18n::Boundary aLineBound; + GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound ); + + /*accessibility::*/TextSegment aTextAtLine; + const ::rtl::OUString rText = GetString(); + aTextAtLine.SegmentText = rText.copy( aLineBound.startPos, + aLineBound.endPos - aLineBound.startPos ); + aTextAtLine.SegmentStart = aLineBound.startPos; + aTextAtLine.SegmentEnd = aLineBound.endPos; + + return aTextAtLine; +} + +/*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret() + throw (uno::RuntimeException) +{ + const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret(); + + if ( nLineNoOfCaret >= 0 && + nLineNoOfCaret < GetPortionData().GetLineCount() ) + { + return getTextAtLineNumber( nLineNoOfCaret ); + } + + return /*accessibility::*/TextSegment(); +} + +sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret() + throw (uno::RuntimeException) +{ + const sal_Int32 nCaretPos = getCaretPosition(); + const sal_Int32 nLength = GetString().getLength(); + if ( !IsValidPosition( nCaretPos, nLength ) ) + { + return -1; + } + + sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos ); + + // special handling for cursor positioned at end of text line via End key + if ( nCaretPos != 0 ) + { + i18n::Boundary aLineBound; + GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound ); + if ( nCaretPos == aLineBound.startPos ) + { + SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell(); + if ( pCrsrShell != 0 ) + { + const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos ); + + const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect(); + // translate core coordinates into accessibility coordinates + Window *pWin = GetWindow(); + CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); + + Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() )); + + SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root + Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() ); + aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() ); + + // convert into AWT Rectangle + const awt::Rectangle aCursorRect( aScreenRect.Left(), + aScreenRect.Top(), + aScreenRect.GetWidth(), + aScreenRect.GetHeight() ); + + if ( aCharRect.X != aCursorRect.X || + aCharRect.Y != aCursorRect.Y ) + { + --nLineNo; + } + } + } + } + + return nLineNo; +} + +// #i108125# +void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + mpParaChangeTrackInfo->reset(); + + CheckRegistration( pOld, pNew ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accpara.hxx b/sw/source/core/access/accpara.hxx new file mode 100644 index 000000000000..d3092e2326f3 --- /dev/null +++ b/sw/source/core/access/accpara.hxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCPARA_HXX +#define _ACCPARA_HXX + +#include <acccontext.hxx> +#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleHypertext.hpp> +#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp> +#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp> +#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp> +#include <boost/unordered_map.hpp> +#include <accselectionhelper.hxx> +#include <calbck.hxx> // #i108125# + +class SwTxtFrm; +class SwTxtNode; +class SwPaM; +class SwAccessiblePortionData; +class SwAccessibleHyperTextData; +class SwXTextPortion; +class SwParaChangeTrackingInfo; //#i108125# + +namespace rtl { class OUString; } +namespace com { namespace sun { namespace star { + namespace i18n { struct Boundary; } + namespace accessibility { class XAccessibleHyperlink; } +} } } + +typedef ::boost::unordered_map< ::rtl::OUString, + ::com::sun::star::beans::PropertyValue, + ::rtl::OUStringHash, + ::std::equal_to< ::rtl::OUString > > tAccParaPropValMap; + +class SwAccessibleParagraph : + public SwClient, // #i108125# + public SwAccessibleContext, + public ::com::sun::star::accessibility::XAccessibleEditableText, + public com::sun::star::accessibility::XAccessibleSelection, + public com::sun::star::accessibility::XAccessibleHypertext, + public com::sun::star::accessibility::XAccessibleTextMarkup, + public com::sun::star::accessibility::XAccessibleMultiLineText, + public ::com::sun::star::accessibility::XAccessibleTextAttributes +{ + friend class SwAccessibleHyperlink; + + ::rtl::OUString sDesc; // protected by base classes mutex + + /// data for this paragraph's text portions; this contains the + /// mapping from the core 'model string' to the accessible text + /// string. + /// pPortionData may be NULL; it should only be accessed through the + /// Get/Clear/Has/UpdatePortionData() methods + SwAccessiblePortionData* pPortionData; + SwAccessibleHyperTextData *pHyperTextData; + + sal_Int32 nOldCaretPos; // The 'old' caret pos. It's only valid as long + // as the cursor is inside this object (protected by + // mutex) + + sal_Bool bIsHeading; // protected by base classes mutex + + // implementation for XAccessibleSelection + SwAccessibleSelectionHelper aSelectionHelper; + + SwParaChangeTrackingInfo* mpParaChangeTrackInfo; // #i108125# + + /// get the SwTxtNode (requires frame; check before) + const SwTxtNode* GetTxtNode() const; + + /// get the (accessible) text string (requires frame; check before) + ::rtl::OUString GetString(); + + ::rtl::OUString GetDescription(); + + // get the current care position + sal_Int32 GetCaretPos(); + + /// determine the current selection. Fill the values with + /// -1 if there is no selection in the this paragraph + sal_Bool GetSelection(sal_Int32& nStart, sal_Int32& nEnd); + + // helper for GetSelection and getCaretPosition + // #i27301# - add parameter <_bForSelection>, which indicates, + // if the cursor is retrieved for selection or for caret position. + SwPaM* GetCursor( const bool _bForSelection ); + + /// for cut/copy/paste: execute a particular slot at the view shell + void ExecuteAtViewShell( sal_uInt16 nSlot ); + + /// helper method for get/setAttributes + /// (for the special case of (nEndIndex==-1) a single character will + /// be selected) + SwXTextPortion* CreateUnoPortion( sal_Int32 nStart, sal_Int32 nEnd ); + + + // methods for checking the parameter range: + + /// does nPos point to a char? + sal_Bool IsValidChar(sal_Int32 nPos, sal_Int32 nLength); + + /// does nPos point to a position? (may be behind the last character) + sal_Bool IsValidPosition(sal_Int32 nPos, sal_Int32 nLength); + + /// is nBegin...nEnd a valid range? (nEnd points past the last character) + sal_Bool IsValidRange(sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength); + + /// Ensure ordered range (i.e. nBegin is smaller then nEnd) + inline void OrderRange(sal_Int32& nBegin, sal_Int32& nEnd) + { + if( nBegin > nEnd ) + { + sal_Int32 nTmp = nBegin; nBegin = nEnd; nEnd = nTmp; + } + } + + // #i63870# + void _getDefaultAttributesImpl( + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes, + tAccParaPropValMap& rDefAttrSeq, + const bool bOnlyCharAttrs = false ); + void _getRunAttributesImpl( + const sal_Int32 nIndex, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes, + tAccParaPropValMap& rRunAttrSeq ); + // <-- + +public: + + sal_Bool IsHeading() const; + +protected: + + // Set states for getAccessibleStateSet. + // This drived class additinaly sets MULTILINE(1), MULTISELECTABLE(+), + // FOCUSABLE(+) and FOCUSED(+) + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + virtual void _InvalidateContent( sal_Bool bVisibleDataFired ); + + virtual void _InvalidateCursorPos(); + virtual void _InvalidateFocus(); + + virtual ~SwAccessibleParagraph(); + + //===== handling of data for the text portions =========================== + + /// force update of new portion data + void UpdatePortionData() + throw( com::sun::star::uno::RuntimeException ); + + /// remove the current portion data + void ClearPortionData(); + + /// get portion data; update if necesary + SwAccessiblePortionData& GetPortionData() + throw( com::sun::star::uno::RuntimeException ) + { + if( pPortionData == NULL ) + UpdatePortionData(); + return *pPortionData; + } + + /// determine if portion data is currently available + sal_Bool HasPortionData() { return (pPortionData != NULL); } + + + //===== helpers for word boundaries ==================================== + + sal_Bool GetCharBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + sal_Bool GetWordBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + sal_Bool GetSentenceBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + sal_Bool GetLineBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + sal_Bool GetParagraphBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + sal_Bool GetAttributeBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + sal_Bool GetGlyphBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos ); + + /// get boundaries of word/sentence/etc. for specified text type + /// Does all argument checking, and then delegates to helper methods above. + sal_Bool GetTextBoundary( com::sun::star::i18n::Boundary& rBound, + const rtl::OUString& rText, + sal_Int32 nPos, + sal_Int16 aTextType ) + throw ( + ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew); + +public: + + SwAccessibleParagraph( SwAccessibleMap& rInitMap, + const SwTxtFrm& rTxtFrm ); + + inline operator ::com::sun::star::accessibility::XAccessibleText *(); + + virtual sal_Bool HasCursor(); // required by map to remember that object + + //===== XAccessibleContext ============================================== + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + /** Return the parents locale or throw exception if this object has no + parent yet/anymore. + */ + virtual ::com::sun::star::lang::Locale SAL_CALL + getLocale (void) + throw (::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException); + + /** #i27138# - paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO */ + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleRelationSet> SAL_CALL + getAccessibleRelationSet (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== XAccessibleComponent ============================================ + + virtual void SAL_CALL grabFocus() + throw (::com::sun::star::uno::RuntimeException); + // #i71385# + virtual sal_Int32 SAL_CALL getForeground() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground() + throw (::com::sun::star::uno::RuntimeException); + // <-- + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + + //===== XInterface ====================================================== + + // (XInterface methods need to be implemented to disambiguate + // between those inherited through SwAcessibleContext and + // XAccessibleEditableText). + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire( ) throw () + { SwAccessibleContext::acquire(); }; + + virtual void SAL_CALL release( ) throw () + { SwAccessibleContext::release(); }; + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + //===== XAccesibleText ================================================== + virtual sal_Int32 SAL_CALL getCaretPosition( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL setCaretPosition( sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Unicode SAL_CALL getCharacter( sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getCharacterBounds( sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getCharacterCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getIndexAtPoint( const ::com::sun::star::awt::Point& aPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getSelectedText( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getSelectionStart( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getSelectionEnd( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getText( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::accessibility::TextSegment SAL_CALL getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::accessibility::TextSegment SAL_CALL getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::accessibility::TextSegment SAL_CALL getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + //===== XAccesibleEditableText ========================================== + virtual sal_Bool SAL_CALL cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL pasteText( sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL insertText( const ::rtl::OUString& sText, sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL replaceText( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const ::rtl::OUString& sReplacement ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL setAttributes( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aAttributeSet ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL setText( const ::rtl::OUString& sText ) throw (::com::sun::star::uno::RuntimeException); + + //===== XAccessibleSelection ============================================ + virtual void SAL_CALL selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL clearAccessibleSelection( ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL selectAllAccessibleChildren( ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) + throw ( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + // index has to be treated as global child index. + virtual void SAL_CALL deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + //===== XAccessibleHypertext ============================================ + virtual sal_Int32 SAL_CALL getHyperLinkCount() + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleHyperlink > + SAL_CALL getHyperLink( sal_Int32 nLinkIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getHyperLinkIndex( sal_Int32 nCharIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + // #i71360# + //===== XAccesibleTextMarkup ============================================ + virtual sal_Int32 SAL_CALL getTextMarkupCount( sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::accessibility::TextSegment SAL_CALL + getTextMarkup( sal_Int32 nTextMarkupIndex, + sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::accessibility::TextSegment > SAL_CALL + getTextMarkupAtIndex( sal_Int32 nCharIndex, + sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + // <-- + + // #i89175# + //===== XAccessibleMultiLineText ======================================== + virtual sal_Int32 SAL_CALL getLineNumberAtIndex( sal_Int32 nIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::accessibility::TextSegment SAL_CALL + getTextAtLineNumber( sal_Int32 nLineNo ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::accessibility::TextSegment SAL_CALL + getTextAtLineWithCaret() + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getNumberOfLineWithCaret() + throw (::com::sun::star::uno::RuntimeException); + // <-- + + // #i63870# + //===== XAccesibleTextAttributes ======================================== + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getDefaultAttributes( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getRunAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + // <-- +}; + +inline SwAccessibleParagraph::operator ::com::sun::star::accessibility::XAccessibleText *() +{ + return static_cast< + ::com::sun::star::accessibility::XAccessibleEditableText * >( this ); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accportions.cxx b/sw/source/core/access/accportions.cxx new file mode 100644 index 000000000000..0142391027b8 --- /dev/null +++ b/sw/source/core/access/accportions.cxx @@ -0,0 +1,750 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include "accportions.hxx" +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/i18n/Boundary.hpp> +#include <txttypes.hxx> + +// for portion replacement in Special() +#include "access.hrc" +#include <tools/resid.hxx> +#include "viewopt.hxx" + +// for GetWordBoundary(...), GetSentenceBoundary(...): +#include <breakit.hxx> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <ndtxt.hxx> + +// for FillSpecialPos(...) +#include "crstate.hxx" + +// for SwAccessibleContext::GetResource() +#include "acccontext.hxx" + +// for Post-It replacement text: +#include "txatbase.hxx" +#include "fmtfld.hxx" +#include "fldbas.hxx" +#include "docufld.hxx" + +// for in-line graphics replacement: +#include "ndindex.hxx" +#include "ndnotxt.hxx" +#include "fmtflcnt.hxx" +#include "frmfmt.hxx" +#include "fmtcntnt.hxx" + + +using namespace ::com::sun::star; + +using rtl::OUString; +using rtl::OUStringBuffer; +using i18n::Boundary; + + +// 'portion type' for terminating portions +#define POR_TERMINATE 0 + + +// portion attributes +#define PORATTR_SPECIAL 1 +#define PORATTR_READONLY 2 +#define PORATTR_GRAY 4 +#define PORATTR_TERM 128 + +SwAccessiblePortionData::SwAccessiblePortionData( + const SwTxtNode* pTxtNd, + const SwViewOption* pViewOpt ) : + SwPortionHandler(), + pTxtNode( pTxtNd ), + aBuffer(), + nModelPosition( 0 ), + bFinished( sal_False ), + pViewOptions( pViewOpt ), + sAccessibleString(), + aLineBreaks(), + aModelPositions(), + aAccessiblePositions(), + pSentences( 0 ), + nBeforePortions( 0 ), + bLastIsSpecial( sal_False ) +{ + DBG_ASSERT( pTxtNode != NULL, "Text node is needed!" ); + + // reserve some space to reduce memory allocations + aLineBreaks.reserve( 5 ); + aModelPositions.reserve( 10 ); + aAccessiblePositions.reserve( 10 ); + + // always include 'first' line-break position + aLineBreaks.push_back( 0 ); +} + +SwAccessiblePortionData::~SwAccessiblePortionData() +{ + delete pSentences; +} + +void SwAccessiblePortionData::Text(sal_uInt16 nLength, sal_uInt16 nType) +{ + DBG_ASSERT( (nModelPosition + nLength) <= pTxtNode->GetTxt().Len(), + "portion exceeds model string!" ); + + DBG_ASSERT( !bFinished, "We are already done!" ); + + // ignore zero-length portions + if( nLength == 0 ) + return; + + // store 'old' positions + aModelPositions.push_back( nModelPosition ); + aAccessiblePositions.push_back( aBuffer.getLength() ); + + // store portion attributes + sal_uInt8 nAttr = IsGrayPortionType(nType) ? PORATTR_GRAY : 0; + aPortionAttrs.push_back( nAttr ); + + // update buffer + nModelPosition + aBuffer.append( OUString( + pTxtNode->GetTxt().Copy( + static_cast<sal_uInt16>( nModelPosition ), + nLength ) ) ); + nModelPosition += nLength; + + bLastIsSpecial = sal_False; +} + +void SwAccessiblePortionData::Special( + sal_uInt16 nLength, const String& rText, sal_uInt16 nType) +{ + DBG_ASSERT( nModelPosition >= 0, "illegal position" ); + DBG_ASSERT( (nModelPosition + nLength) <= pTxtNode->GetTxt().Len(), + "portion exceeds model string!" ); + + DBG_ASSERT( !bFinished, "We are already done!" ); + + // construct string with representation; either directly from + // rText, or use resources for special case portions + String sDisplay; + switch( nType ) + { + case POR_POSTITS: + case POR_FLYCNT: + case POR_GRFNUM: + sDisplay = String(sal_Unicode(0xfffc)); + + break; + case POR_NUMBER: + { + OUStringBuffer aTmpBuffer( rText.Len() + 1 ); + aTmpBuffer.append( rText ); + aTmpBuffer.append( sal_Unicode(' ') ); + sDisplay = aTmpBuffer.makeStringAndClear(); + break; + } + // #i111768# - apply patch from kstribley: + // Include the control characters. + case POR_CONTROLCHAR: + { + OUStringBuffer aTmpBuffer( rText.Len() + 1 ); + aTmpBuffer.append( rText ); + aTmpBuffer.append( pTxtNode->GetTxt().GetChar(nModelPosition) ); + sDisplay = aTmpBuffer.makeStringAndClear(); + break; + } + // <-- + default: + sDisplay = rText; + break; + } + + // ignore zero/zero portions (except for terminators) + if( (nLength == 0) && (sDisplay.Len() == 0) && (nType != POR_TERMINATE) ) + return; + + // special treatment for zero length portion at the beginning: + // count as 'before' portion + if( ( nLength == 0 ) && ( nModelPosition == 0 ) ) + nBeforePortions++; + + // store the 'old' positions + aModelPositions.push_back( nModelPosition ); + aAccessiblePositions.push_back( aBuffer.getLength() ); + + // store portion attributes + sal_uInt8 nAttr = PORATTR_SPECIAL; + if( IsGrayPortionType(nType) ) nAttr |= PORATTR_GRAY; + if( nLength == 0 ) nAttr |= PORATTR_READONLY; + if( nType == POR_TERMINATE ) nAttr |= PORATTR_TERM; + aPortionAttrs.push_back( nAttr ); + + // update buffer + nModelPosition + aBuffer.append( OUString(sDisplay) ); + nModelPosition += nLength; + + // remember 'last' special portion (unless it's our own 'closing' + // portions from 'Finish()' + if( nType != POR_TERMINATE ) + bLastIsSpecial = sal_True; +} + +void SwAccessiblePortionData::LineBreak() +{ + DBG_ASSERT( !bFinished, "We are already done!" ); + + aLineBreaks.push_back( aBuffer.getLength() ); +} + +void SwAccessiblePortionData::Skip(sal_uInt16 nLength) +{ + DBG_ASSERT( !bFinished, "We are already done!" ); + DBG_ASSERT( aModelPositions.size() == 0, "Never Skip() after portions" ); + DBG_ASSERT( nLength <= pTxtNode->GetTxt().Len(), "skip exceeds model string!" ); + + nModelPosition += nLength; +} + +void SwAccessiblePortionData::Finish() +{ + DBG_ASSERT( !bFinished, "We are already done!" ); + + // include terminator values: always include two 'last character' + // markers in the position arrays to make sure we always find one + // position before the end + Special( 0, String(), POR_TERMINATE ); + Special( 0, String(), POR_TERMINATE ); + LineBreak(); + LineBreak(); + + sAccessibleString = aBuffer.makeStringAndClear(); + bFinished = sal_True; +} + + +sal_Bool SwAccessiblePortionData::IsPortionAttrSet( + size_t nPortionNo, sal_uInt8 nAttr ) const +{ + DBG_ASSERT( nPortionNo < aPortionAttrs.size(), + "Illegal portion number" ); + return (aPortionAttrs[nPortionNo] & nAttr) != 0; +} + +sal_Bool SwAccessiblePortionData::IsSpecialPortion( size_t nPortionNo ) const +{ + return IsPortionAttrSet(nPortionNo, PORATTR_SPECIAL); +} + +sal_Bool SwAccessiblePortionData::IsReadOnlyPortion( size_t nPortionNo ) const +{ + return IsPortionAttrSet(nPortionNo, PORATTR_READONLY); +} + +sal_Bool SwAccessiblePortionData::IsGrayPortionType( sal_uInt16 nType ) const +{ + // gray portions? + // Compare with: inftxt.cxx, SwTxtPaintInfo::DrawViewOpt(...) + sal_Bool bGray = sal_False; + switch( nType ) + { + case POR_FTN: + case POR_ISOREF: + case POR_REF: + case POR_QUOVADIS: + case POR_NUMBER: + case POR_FLD: + case POR_URL: + case POR_ISOTOX: + case POR_TOX: + case POR_HIDDEN: + bGray = !pViewOptions->IsPagePreview() && + !pViewOptions->IsReadonly() && SwViewOption::IsFieldShadings(); + break; + case POR_TAB: bGray = pViewOptions->IsTab(); break; + case POR_SOFTHYPH: bGray = pViewOptions->IsSoftHyph(); break; + case POR_BLANK: bGray = pViewOptions->IsHardBlank(); break; + default: + break; // bGray is false + } + return bGray; +} + + +const OUString& SwAccessiblePortionData::GetAccessibleString() const +{ + DBG_ASSERT( bFinished, "Shouldn't call this before we are done!" ); + + return sAccessibleString; +} + + +void SwAccessiblePortionData::GetLineBoundary( + Boundary& rBound, + sal_Int32 nPos ) const +{ + FillBoundary( rBound, aLineBreaks, + FindBreak( aLineBreaks, nPos ) ); +} + +// #i89175# +sal_Int32 SwAccessiblePortionData::GetLineCount() const +{ + size_t nBreaks = aLineBreaks.size(); + // A non-empty paragraph has at least 4 breaks: one for each line3 and + // 3 additional ones. + // An empty paragraph has 3 breaks. + // Less than 3 breaks is an error case. + sal_Int32 nLineCount = ( nBreaks > 3 ) + ? nBreaks - 3 + : ( ( nBreaks == 3 ) ? 1 : 0 ); + return nLineCount; +} + +sal_Int32 SwAccessiblePortionData::GetLineNo( const sal_Int32 nPos ) const +{ + sal_Int32 nLineNo = FindBreak( aLineBreaks, nPos ); + + // handling of position after last character + const sal_Int32 nLineCount( GetLineCount() ); + if ( nLineNo >= nLineCount ) + { + nLineNo = nLineCount - 1; + } + + return nLineNo; +} + +void SwAccessiblePortionData::GetBoundaryOfLine( const sal_Int32 nLineNo, + i18n::Boundary& rLineBound ) +{ + FillBoundary( rLineBound, aLineBreaks, nLineNo ); +} +// <-- + +void SwAccessiblePortionData::GetLastLineBoundary( + Boundary& rBound ) const +{ + DBG_ASSERT( aLineBreaks.size() >= 2, "need min + max value" ); + + // The last two positions except the two deleimiters are the ones + // we are looking for, except for empty paragraphs (nBreaks==3) + size_t nBreaks = aLineBreaks.size(); + FillBoundary( rBound, aLineBreaks, nBreaks <= 3 ? 0 : nBreaks-4 ); +} + +sal_uInt16 SwAccessiblePortionData::GetModelPosition( sal_Int32 nPos ) const +{ + DBG_ASSERT( nPos >= 0, "illegal position" ); + DBG_ASSERT( nPos <= sAccessibleString.getLength(), "illegal position" ); + + // find the portion number + size_t nPortionNo = FindBreak( aAccessiblePositions, nPos ); + + // get model portion size + sal_Int32 nStartPos = aModelPositions[nPortionNo]; + + // if it's a non-special portion, move into the portion, else + // return the portion start + if( ! IsSpecialPortion( nPortionNo ) ) + { + // 'wide' portions have to be of the same width + DBG_ASSERT( ( aModelPositions[nPortionNo+1] - nStartPos ) == + ( aAccessiblePositions[nPortionNo+1] - + aAccessiblePositions[nPortionNo] ), + "accesability portion disagrees with text model" ); + + sal_Int32 nWithinPortion = nPos - aAccessiblePositions[nPortionNo]; + nStartPos += nWithinPortion; + } + // else: return nStartPos unmodified + + DBG_ASSERT( (nStartPos >= 0) && (nStartPos < USHRT_MAX), + "How can the SwTxtNode have so many characters?" ); + return static_cast<sal_uInt16>(nStartPos); +} + +void SwAccessiblePortionData::FillBoundary( + Boundary& rBound, + const Positions_t& rPositions, + size_t nPos ) const +{ + rBound.startPos = rPositions[nPos]; + rBound.endPos = rPositions[nPos+1]; +} + + +size_t SwAccessiblePortionData::FindBreak( + const Positions_t& rPositions, + sal_Int32 nValue ) const +{ + DBG_ASSERT( rPositions.size() >= 2, "need min + max value" ); + DBG_ASSERT( rPositions[0] <= nValue, "need min value" ); + DBG_ASSERT( rPositions[rPositions.size()-1] >= nValue, + "need first terminator value" ); + DBG_ASSERT( rPositions[rPositions.size()-2] >= nValue, + "need second terminator value" ); + + size_t nMin = 0; + size_t nMax = rPositions.size()-2; + + // loop until no more than two candidates are left + while( nMin+1 < nMax ) + { + // check loop invariants + DBG_ASSERT( ( (nMin == 0) && (rPositions[nMin] <= nValue) ) || + ( (nMin != 0) && (rPositions[nMin] < nValue) ), + "minvalue not minimal" ); + DBG_ASSERT( nValue <= rPositions[nMax], "max value not maximal" ); + + // get middle (and ensure progress) + size_t nMiddle = (nMin + nMax)/2; + DBG_ASSERT( nMin < nMiddle, "progress?" ); + DBG_ASSERT( nMiddle < nMax, "progress?" ); + + // check array + DBG_ASSERT( rPositions[nMin] <= rPositions[nMiddle], + "garbled positions array" ); + DBG_ASSERT( rPositions[nMiddle] <= rPositions[nMax], + "garbled positions array" ); + + if( nValue > rPositions[nMiddle] ) + nMin = nMiddle; + else + nMax = nMiddle; + } + + // only two are left; we only need to check which one is the winner + DBG_ASSERT( (nMax == nMin) || (nMax == nMin+1), "only two left" ); + if( (rPositions[nMin] < nValue) && (rPositions[nMin+1] <= nValue) ) + nMin = nMin+1; + + // finally, check to see whether the returned value is the 'right' position + DBG_ASSERT( rPositions[nMin] <= nValue, "not smaller or equal" ); + DBG_ASSERT( nValue <= rPositions[nMin+1], "not equal or larger" ); + DBG_ASSERT( (nMin == 0) || (rPositions[nMin-1] <= nValue), + "earlier value should have been returned" ); + + DBG_ASSERT( nMin < rPositions.size()-1, + "shouldn't return last position (due to termintator values)" ); + + return nMin; +} + +size_t SwAccessiblePortionData::FindLastBreak( + const Positions_t& rPositions, + sal_Int32 nValue ) const +{ + size_t nResult = FindBreak( rPositions, nValue ); + + // skip 'zero-length' portions + // #i70538# consider size of <rPosition> and ignore last entry + while ( nResult < rPositions.size() - 2 && + rPositions[nResult+1] <= nValue ) + { + nResult++; + } + // <-- + + return nResult; +} + + +void SwAccessiblePortionData::GetSentenceBoundary( + Boundary& rBound, + sal_Int32 nPos ) +{ + DBG_ASSERT( nPos >= 0, "illegal position; check before" ); + DBG_ASSERT( nPos < sAccessibleString.getLength(), "illegal position" ); + + if( pSentences == NULL ) + { + DBG_ASSERT( pBreakIt != NULL, "We always need a break." ); + DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." ); + if( pBreakIt->GetBreakIter().is() ) + { + pSentences = new Positions_t(); + pSentences->reserve(10); + + // use xBreak->endOfSentence to iterate over all words; store + // positions in pSentences + sal_Int32 nCurrent = 0; + sal_Int32 nLength = sAccessibleString.getLength(); + do + { + pSentences->push_back( nCurrent ); + + sal_uInt16 nModelPos = GetModelPosition( nCurrent ); + + sal_Int32 nNew = pBreakIt->GetBreakIter()->endOfSentence( + sAccessibleString, nCurrent, + pBreakIt->GetLocale(pTxtNode->GetLang(nModelPos)) ) + 1; + + if( (nNew < 0) && (nNew > nLength) ) + nNew = nLength; + else if (nNew <= nCurrent) + nNew = nCurrent + 1; // ensure forward progress + + nCurrent = nNew; + } + while (nCurrent < nLength); + + // finish with two terminators + pSentences->push_back( nLength ); + pSentences->push_back( nLength ); + } + else + { + // no break iterator -> empty word + rBound.startPos = 0; + rBound.endPos = 0; + return; + } + } + + FillBoundary( rBound, *pSentences, FindBreak( *pSentences, nPos ) ); +} + +void SwAccessiblePortionData::GetAttributeBoundary( + Boundary& rBound, + sal_Int32 nPos) const +{ + DBG_ASSERT( pTxtNode != NULL, "Need SwTxtNode!" ); + + // attribute boundaries can only occur on portion boundaries + FillBoundary( rBound, aAccessiblePositions, + FindBreak( aAccessiblePositions, nPos ) ); +} + + +sal_Int32 SwAccessiblePortionData::GetAccessiblePosition( sal_uInt16 nPos ) const +{ + DBG_ASSERT( nPos <= pTxtNode->GetTxt().Len(), "illegal position" ); + + // find the portion number + // #i70538# - consider "empty" model portions - e.g. number portion + size_t nPortionNo = FindLastBreak( aModelPositions, + static_cast<sal_Int32>(nPos) ); + + sal_Int32 nRet = aAccessiblePositions[nPortionNo]; + + // if the model portion has more than one position, go into it; + // else return that position + sal_Int32 nStartPos = aModelPositions[nPortionNo]; + sal_Int32 nEndPos = aModelPositions[nPortionNo+1]; + if( (nEndPos - nStartPos) > 1 ) + { + // 'wide' portions have to be of the same width + DBG_ASSERT( ( nEndPos - nStartPos ) == + ( aAccessiblePositions[nPortionNo+1] - + aAccessiblePositions[nPortionNo] ), + "accesability portion disagrees with text model" ); + + sal_Int32 nWithinPortion = nPos - aModelPositions[nPortionNo]; + nRet += nWithinPortion; + } + // else: return nRet unmodified + + DBG_ASSERT( (nRet >= 0) && (nRet <= sAccessibleString.getLength()), + "too long!" ); + return nRet; +} + +sal_uInt16 SwAccessiblePortionData::FillSpecialPos( + sal_Int32 nPos, + SwSpecialPos& rPos, + SwSpecialPos*& rpPos ) const +{ + size_t nPortionNo = FindLastBreak( aAccessiblePositions, nPos ); + + sal_uInt8 nExtend(SP_EXTEND_RANGE_NONE); + sal_Int32 nRefPos(0); + sal_Int32 nModelPos(0); + + if( nPortionNo < nBeforePortions ) + { + nExtend = SP_EXTEND_RANGE_BEFORE; + rpPos = &rPos; + } + else + { + sal_Int32 nModelEndPos = aModelPositions[nPortionNo+1]; + nModelPos = aModelPositions[nPortionNo]; + + // skip backwards over zero-length portions, since GetCharRect() + // counts all model-zero-length portions as belonging to the + // previus portion + size_t nCorePortionNo = nPortionNo; + while( nModelPos == nModelEndPos ) + { + nCorePortionNo--; + nModelEndPos = nModelPos; + nModelPos = aModelPositions[nCorePortionNo]; + + DBG_ASSERT( nModelPos >= 0, "Can't happen." ); + DBG_ASSERT( nCorePortionNo >= nBeforePortions, "Can't happen." ); + } + DBG_ASSERT( nModelPos != nModelEndPos, + "portion with core-representation expected" ); + + // if we have anything except plain text, compute nExtend + nRefPos + if( (nModelEndPos - nModelPos == 1) && + (pTxtNode->GetTxt().GetChar(static_cast<sal_uInt16>(nModelPos)) != + sAccessibleString.getStr()[nPos]) ) + { + // case 1: a one-character, non-text portion + // reference position is the first accessibilty for our + // core portion + nRefPos = aAccessiblePositions[ nCorePortionNo ]; + nExtend = SP_EXTEND_RANGE_NONE; + rpPos = &rPos; + } + else if(nPortionNo != nCorePortionNo) + { + // case 2: a multi-character (text!) portion, followed by + // zero-length portions + // reference position is the first character of the next + // portion, and we are 'behind' + nRefPos = aAccessiblePositions[ nCorePortionNo+1 ]; + nExtend = SP_EXTEND_RANGE_BEHIND; + rpPos = &rPos; + } + else + { + // case 3: regular text portion + DBG_ASSERT( ( nModelEndPos - nModelPos ) == + ( aAccessiblePositions[nPortionNo+1] - + aAccessiblePositions[nPortionNo] ), + "text portion expected" ); + + nModelPos += nPos - aAccessiblePositions[ nPortionNo ]; + rpPos = NULL; + } + } + if( rpPos != NULL ) + { + DBG_ASSERT( rpPos == &rPos, "Yes!" ); + DBG_ASSERT( nRefPos <= nPos, "wrong reference" ); + DBG_ASSERT( (nExtend == SP_EXTEND_RANGE_NONE) || + (nExtend == SP_EXTEND_RANGE_BEFORE) || + (nExtend == SP_EXTEND_RANGE_BEHIND), "need extend" ); + + // get the line number, and adjust nRefPos for the line + // (if necessary) + size_t nRefLine = FindBreak( aLineBreaks, nRefPos ); + size_t nMyLine = FindBreak( aLineBreaks, nPos ); + sal_uInt16 nLineOffset = static_cast<sal_uInt16>( nMyLine - nRefLine ); + if( nLineOffset != 0 ) + nRefPos = aLineBreaks[ nMyLine ]; + + // fill char offset and 'special position' + rPos.nCharOfst = static_cast<sal_uInt16>( nPos - nRefPos ); + rPos.nExtendRange = nExtend; + rPos.nLineOfst = nLineOffset; + } + + return static_cast<sal_uInt16>( nModelPos ); +} + +void SwAccessiblePortionData::AdjustAndCheck( + sal_Int32 nPos, + size_t& nPortionNo, + sal_uInt16& nCorePos, + sal_Bool& bEdit) const +{ + // find portion and get mode position + nPortionNo = FindBreak( aAccessiblePositions, nPos ); + nCorePos = static_cast<sal_uInt16>( aModelPositions[ nPortionNo ] ); + + // for special portions, make sure we're on a portion boundary + // for text portions, add the in-portion offset + if( IsSpecialPortion( nPortionNo ) ) + bEdit &= nPos == aAccessiblePositions[nPortionNo]; + else + nCorePos = static_cast<sal_uInt16>( nCorePos + + nPos - aAccessiblePositions[nPortionNo] ); +} + +sal_Bool SwAccessiblePortionData::GetEditableRange( + sal_Int32 nStart, sal_Int32 nEnd, + sal_uInt16& nCoreStart, sal_uInt16& nCoreEnd ) const +{ + sal_Bool bIsEditable = sal_True; + + // get start and end portions + size_t nStartPortion, nEndPortion; + AdjustAndCheck( nStart, nStartPortion, nCoreStart, bIsEditable ); + AdjustAndCheck( nEnd, nEndPortion, nCoreEnd, bIsEditable ); + + // iterate over portions, and make sure there is no read-only portion + // in-between + size_t nLastPortion = nEndPortion; + + // don't count last portion if we're in front of a special portion + if( IsSpecialPortion(nLastPortion) ) + { + if (nLastPortion > 0) + nLastPortion--; + else + // special case: because size_t is usually unsigned, we can't just + // decrease nLastPortion to -1 (which would normally do the job, so + // this whole if wouldn't be needed). Instead, we'll do this + // special case and just increae the start portion beyond the last + // portion to make sure the loop below will have zero iteration. + nStartPortion = nLastPortion + 1; + } + + for( size_t nPor = nStartPortion; nPor <= nLastPortion; nPor ++ ) + { + bIsEditable &= ! IsReadOnlyPortion( nPor ); + } + + return bIsEditable; +} + +sal_Bool SwAccessiblePortionData::IsValidCorePosition( sal_uInt16 nPos ) const +{ + // a position is valid its within the model positions that we know + return ( aModelPositions[0] <= nPos ) && + ( nPos <= aModelPositions[ aModelPositions.size()-1 ] ); +} + +sal_uInt16 SwAccessiblePortionData::GetFirstValidCorePosition() const +{ + return static_cast<sal_uInt16>( aModelPositions[0] ); +} + +sal_uInt16 SwAccessiblePortionData::GetLastValidCorePosition() const +{ + return static_cast<sal_uInt16>( aModelPositions[ aModelPositions.size()-1 ] ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accportions.hxx b/sw/source/core/access/accportions.hxx new file mode 100644 index 000000000000..ef04e7ff56eb --- /dev/null +++ b/sw/source/core/access/accportions.hxx @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCPORTIONS_HXX +#define _ACCPORTIONS_HXX +#include <SwPortionHandler.hxx> +#include <sal/types.h> +#include <rtl/ustrbuf.hxx> +#include <vector> + +class String; +class SwTxtNode; +struct SwSpecialPos; +class SwViewOption; +namespace com { namespace sun { namespace star { + namespace i18n { struct Boundary; } +} } } + +/** + * collect text portion data from the layout through SwPortionHandler interface + */ +class SwAccessiblePortionData : public SwPortionHandler +{ + // the node this portion is referring to + const SwTxtNode* pTxtNode; + + // variables used while collecting the data + rtl::OUStringBuffer aBuffer; + sal_Int32 nModelPosition; + sal_Bool bFinished; + const SwViewOption* pViewOptions; + + // the accessible string + rtl::OUString sAccessibleString; + + // positions array + // instances of Position_t must always include the minimum and + // maximum positions as first/last elements (to simplify the + // algorithms) + typedef std::vector<sal_Int32> Positions_t; + + Positions_t aLineBreaks; /// position of line breaks + Positions_t aModelPositions; /// position of portion breaks in the model + Positions_t aAccessiblePositions; /// portion breaks in sAccessibleString + + typedef std::vector<sal_uInt8> PortionAttrs_t; + PortionAttrs_t aPortionAttrs; /// additional portion attributes + + Positions_t* pSentences; /// positions of sentence breaks + + size_t nBeforePortions; /// # of portions before first model character + sal_Bool bLastIsSpecial; /// set if last portion was 'Special()' + + /// returns the index of the first position whose value is smaller + /// or equal, and whose following value is equal or larger + size_t FindBreak( const Positions_t& rPositions, sal_Int32 nValue ) const; + + /// like FindBreak, but finds the last equal or larger position + size_t FindLastBreak( const Positions_t& rPositions, sal_Int32 nValue ) const; + + /// fill the boundary with the values from rPositions[nPos] + void FillBoundary(com::sun::star::i18n::Boundary& rBound, + const Positions_t& rPositions, + size_t nPos ) const; + + /// Access to portion attributes + sal_Bool IsPortionAttrSet( size_t nPortionNo, sal_uInt8 nAttr ) const; + sal_Bool IsSpecialPortion( size_t nPortionNo ) const; + sal_Bool IsReadOnlyPortion( size_t nPortionNo ) const; + sal_Bool IsGrayPortionType( sal_uInt16 nType ) const; + + // helper method for GetEditableRange(...): + void AdjustAndCheck( sal_Int32 nPos, size_t& nPortionNo, + sal_uInt16& nCorePos, sal_Bool& bEdit ) const; + +public: + SwAccessiblePortionData( const SwTxtNode* pTxtNd, + const SwViewOption* pViewOpt = NULL ); + virtual ~SwAccessiblePortionData(); + + // SwPortionHandler methods + virtual void Text(sal_uInt16 nLength, sal_uInt16 nType); + virtual void Special(sal_uInt16 nLength, const String& rText, sal_uInt16 nType); + virtual void LineBreak(); + virtual void Skip(sal_uInt16 nLength); + virtual void Finish(); + + + // access to the portion data + + /// get the text string, as presented by the layout + const rtl::OUString& GetAccessibleString() const; + + /// get the start & end positions of the sentence + void GetLineBoundary( com::sun::star::i18n::Boundary& rBound, + sal_Int32 nPos ) const; + + // get start and end position of the last line + void GetLastLineBoundary( com::sun::star::i18n::Boundary& rBound ) const; + + // #i89175# + sal_Int32 GetLineCount() const; + sal_Int32 GetLineNo( const sal_Int32 nPos ) const; + void GetBoundaryOfLine( const sal_Int32 nLineNo, + com::sun::star::i18n::Boundary& rLineBound ); + // <-- + + /// get the position in the model string for a given + /// (accessibility) position + sal_uInt16 GetModelPosition( sal_Int32 nPos ) const; + + /// get the position in the accessibility string for a given model position + sal_Int32 GetAccessiblePosition( sal_uInt16 nPos ) const; + + /// fill a SwSpecialPos structure, suitable for calling + /// SwTxtFrm->GetCharRect + /// Returns the core position, and fills thr rpPos either with NULL or + /// with the &rPos, after putting the appropriate data into it. + sal_uInt16 FillSpecialPos( sal_Int32 nPos, + SwSpecialPos& rPos, + SwSpecialPos*& rpPos ) const; + + + // get boundaries of words/sentences. The data structures are + // created on-demand. + void GetSentenceBoundary( com::sun::star::i18n::Boundary& rBound, + sal_Int32 nPos ); + + // get (a) boundary for attribut change + void GetAttributeBoundary( com::sun::star::i18n::Boundary& rBound, + sal_Int32 nPos ) const; + + /// Convert start and end positions into core positions. + /// @returns true if 'special' portions are included either completely + /// or not at all. This can be used to test whether editing + /// that range would be legal + sal_Bool GetEditableRange( sal_Int32 nStart, sal_Int32 nEnd, + sal_uInt16& nCoreStart, sal_uInt16& nCoreEnd ) const; + + /// Determine whether this core position is valid for these portions. + /// (A paragraph may be split into several frames, e.g. at page + /// boundaries. In this case, only part of a paragraph is represented + /// through this object. This method determines whether one particular + /// position is valid for this object or not.) + sal_Bool IsValidCorePosition( sal_uInt16 nPos ) const; + sal_uInt16 GetFirstValidCorePosition() const; + sal_uInt16 GetLastValidCorePosition() const; +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accpreview.cxx b/sw/source/core/access/accpreview.cxx new file mode 100644 index 000000000000..c656b4000d05 --- /dev/null +++ b/sw/source/core/access/accpreview.cxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <vcl/svapp.hxx> +#include <rtl/uuid.h> +#include "access.hrc" +#include <accpreview.hxx> + +const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextDocumentPageView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleDocumentPageView"; + +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; + +// +// SwAccessiblePreview +// + +SwAccessiblePreview::SwAccessiblePreview( SwAccessibleMap *pMp ) : + SwAccessibleDocumentBase( pMp ) +{ + SetName( GetResource( STR_ACCESS_DOC_NAME ) ); +} + +SwAccessiblePreview::~SwAccessiblePreview() +{ +} + +OUString SwAccessiblePreview::getImplementationName( ) + throw( RuntimeException ) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( sImplementationName ) ); +} + +sal_Bool SwAccessiblePreview::supportsService( const OUString& rServiceName ) + throw( RuntimeException ) +{ + return rServiceName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( sServiceName) ) || + rServiceName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( sAccessibleServiceName ) ); +} + +Sequence<OUString> SwAccessiblePreview::getSupportedServiceNames( ) + throw( RuntimeException ) +{ + Sequence<OUString> aSeq( 2 ); + aSeq[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( sServiceName ) ); + aSeq[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( sAccessibleServiceName ) ); + return aSeq; +} + +Sequence< sal_Int8 > SAL_CALL SwAccessiblePreview::getImplementationId() + throw(RuntimeException) +{ + SolarMutexGuard aGuard; + static Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accpreview.hxx b/sw/source/core/access/accpreview.hxx new file mode 100644 index 000000000000..589811e927c9 --- /dev/null +++ b/sw/source/core/access/accpreview.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCPREVIEW_HXX +#define _ACCPREVIEW_HXX + +#include "accdoc.hxx" + +/** + * accessibility implementation for the page preview. + * The children of the page preview are the pages that are visible in the + * preview. + * + * The vast majority of the implemention logic is inherited from + * SwAccessibleDocumentBase. + */ +class SwAccessiblePreview : public SwAccessibleDocumentBase +{ + virtual ~SwAccessiblePreview(); + +public: + + SwAccessiblePreview( SwAccessibleMap *pMap ); + + + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accselectionhelper.cxx b/sw/source/core/access/accselectionhelper.cxx new file mode 100644 index 000000000000..c3beba54da6e --- /dev/null +++ b/sw/source/core/access/accselectionhelper.cxx @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <accselectionhelper.hxx> + +#include <acccontext.hxx> +#include <accmap.hxx> +#include <svx/AccessibleShape.hxx> +#include <viewsh.hxx> +#include <fesh.hxx> +#include <vcl/svapp.hxx> // for SolarMutex +#include <tools/debug.hxx> +#include <flyfrm.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using ::com::sun::star::accessibility::XAccessible; +using ::com::sun::star::accessibility::XAccessibleContext; +using ::com::sun::star::accessibility::XAccessibleSelection; + +using namespace ::sw::access; + +SwAccessibleSelectionHelper::SwAccessibleSelectionHelper( + SwAccessibleContext& rCtxt ) : + rContext( rCtxt ) +{ +} + +SwAccessibleSelectionHelper::~SwAccessibleSelectionHelper() +{ +} + +SwFEShell* SwAccessibleSelectionHelper::GetFEShell() +{ + DBG_ASSERT( rContext.GetMap() != NULL, "no map?" ); + ViewShell* pViewShell = rContext.GetMap()->GetShell(); + DBG_ASSERT( pViewShell != NULL, + "No view shell? Then what are you looking at?" ); + + SwFEShell* pFEShell = NULL; + if( pViewShell->ISA( SwFEShell ) ) + { + pFEShell = static_cast<SwFEShell*>( pViewShell ); + } + + return pFEShell; +} + +void SwAccessibleSelectionHelper::throwIndexOutOfBoundsException() + throw ( lang::IndexOutOfBoundsException ) +{ + Reference < XAccessibleContext > xThis( &rContext ); + Reference < XAccessibleSelection >xSelThis( xThis, UNO_QUERY ); + lang::IndexOutOfBoundsException aExcept( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("index out of bounds") ), + xSelThis ); \ + throw aExcept; +} + + +//===== XAccessibleSelection ============================================ + +void SwAccessibleSelectionHelper::selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + RuntimeException ) +{ + SolarMutexGuard aGuard; + + // Get the respective child as SwFrm (also do index checking), ... + const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()), + nChildIndex ); + if( !aChild.IsValid() ) + throwIndexOutOfBoundsException(); + + // we can only select fly frames, so we ignore (should: return + // false) all other attempts at child selection + SwFEShell* pFEShell = GetFEShell(); + if( pFEShell != NULL ) + { + const SdrObject *pObj = aChild.GetDrawObject(); + if( pObj ) + rContext.Select( const_cast< SdrObject *>( pObj ), 0==aChild.GetSwFrm()); + } + // no frame shell, or no frame, or no fly frame -> can't select +} + +sal_Bool SwAccessibleSelectionHelper::isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + RuntimeException ) +{ + SolarMutexGuard aGuard; + + // Get the respective child as SwFrm (also do index checking), ... + const SwAccessibleChild aChild = rContext.GetChild( *(rContext.GetMap()), + nChildIndex ); + if( !aChild.IsValid() ) + throwIndexOutOfBoundsException(); + + // ... and compare to the currently selected frame + sal_Bool bRet = sal_False; + SwFEShell* pFEShell = GetFEShell(); + if( pFEShell ) + { + if ( aChild.GetSwFrm() != 0 ) + { + bRet = (pFEShell->GetCurrFlyFrm() == aChild.GetSwFrm()); + } + else if ( aChild.GetDrawObject() ) + { + bRet = pFEShell->IsObjSelected( *aChild.GetDrawObject() ); + } + } + + return bRet; +} + +void SwAccessibleSelectionHelper::clearAccessibleSelection( ) + throw ( RuntimeException ) +{ + // return sal_False // we can't deselect +} + +void SwAccessibleSelectionHelper::selectAllAccessibleChildren( ) + throw ( RuntimeException ) +{ + SolarMutexGuard aGuard; + + // We can select only one. So iterate over the children to find + // the first we can select, and select it. + + SwFEShell* pFEShell = GetFEShell(); + if( pFEShell ) + { + ::std::list< SwAccessibleChild > aChildren; + rContext.GetChildren( *(rContext.GetMap()), aChildren ); + + ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin(); + ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end(); + while( aIter != aEndIter ) + { + const SwAccessibleChild& rChild = *aIter; + const SdrObject* pObj = rChild.GetDrawObject(); + const SwFrm* pFrm = rChild.GetSwFrm(); + if( pObj && !(pFrm != 0 && pFEShell->IsObjSelected()) ) + { + rContext.Select( const_cast< SdrObject *>( pObj ), 0==pFrm ); + if( pFrm ) + break; + } + ++aIter; + } + } +} + +sal_Int32 SwAccessibleSelectionHelper::getSelectedAccessibleChildCount( ) + throw ( RuntimeException ) +{ + SolarMutexGuard aGuard; + + sal_Int32 nCount = 0; + // Only one frame can be selected at a time, and we only frames + // for selectable children. + SwFEShell* pFEShell = GetFEShell(); + if( pFEShell != 0 ) + { + const SwFlyFrm* pFlyFrm = pFEShell->GetCurrFlyFrm(); + if( pFlyFrm ) + { + if( rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) == + rContext.GetFrm() ) + { + nCount = 1; + } + } + else + { + sal_uInt16 nSelObjs = pFEShell->IsObjSelected(); + if( nSelObjs > 0 ) + { + ::std::list< SwAccessibleChild > aChildren; + rContext.GetChildren( *(rContext.GetMap()), aChildren ); + + ::std::list< SwAccessibleChild >::const_iterator aIter = + aChildren.begin(); + ::std::list< SwAccessibleChild >::const_iterator aEndIter = + aChildren.end(); + while( aIter != aEndIter && nCount < nSelObjs ) + { + const SwAccessibleChild& rChild = *aIter; + if( rChild.GetDrawObject() && !rChild.GetSwFrm() && + rContext.GetParent(rChild, rContext.IsInPagePreview()) + == rContext.GetFrm() && + pFEShell->IsObjSelected( *rChild.GetDrawObject() ) ) + { + nCount++; + } + ++aIter; + } + } + } + } + return nCount; +} + +Reference<XAccessible> SwAccessibleSelectionHelper::getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( lang::IndexOutOfBoundsException, + RuntimeException) +{ + SolarMutexGuard aGuard; + + // Since the index is relative to the selected children, and since + // there can be at most one selected frame child, the index must + // be 0, and a selection must exist, otherwise we have to throw an + // lang::IndexOutOfBoundsException + SwFEShell* pFEShell = GetFEShell(); + if( 0 == pFEShell ) + throwIndexOutOfBoundsException(); + + SwAccessibleChild aChild; + const SwFlyFrm *pFlyFrm = pFEShell->GetCurrFlyFrm(); + if( pFlyFrm ) + { + if( 0 == nSelectedChildIndex && + rContext.GetParent( SwAccessibleChild(pFlyFrm), rContext.IsInPagePreview()) == + rContext.GetFrm() ) + { + aChild = pFlyFrm; + } + } + else + { + sal_uInt16 nSelObjs = pFEShell->IsObjSelected(); + if( 0 == nSelObjs || nSelectedChildIndex >= nSelObjs ) + throwIndexOutOfBoundsException(); + + ::std::list< SwAccessibleChild > aChildren; + rContext.GetChildren( *(rContext.GetMap()), aChildren ); + + ::std::list< SwAccessibleChild >::const_iterator aIter = aChildren.begin(); + ::std::list< SwAccessibleChild >::const_iterator aEndIter = aChildren.end(); + while( aIter != aEndIter && !aChild.IsValid() ) + { + const SwAccessibleChild& rChild = *aIter; + if( rChild.GetDrawObject() && !rChild.GetSwFrm() && + rContext.GetParent(rChild, rContext.IsInPagePreview()) == + rContext.GetFrm() && + pFEShell->IsObjSelected( *rChild.GetDrawObject() ) ) + { + if( 0 == nSelectedChildIndex ) + aChild = rChild; + else + --nSelectedChildIndex; + } + ++aIter; + } + } + + if( !aChild.IsValid() ) + throwIndexOutOfBoundsException(); + + DBG_ASSERT( rContext.GetMap() != NULL, "We need the map." ); + Reference< XAccessible > xChild; + if( aChild.GetSwFrm() ) + { + ::rtl::Reference < SwAccessibleContext > xChildImpl( + rContext.GetMap()->GetContextImpl( aChild.GetSwFrm(), + sal_True ) ); + if( xChildImpl.is() ) + { + xChildImpl->SetParent( &rContext ); + xChild = xChildImpl.get(); + } + } + else if ( aChild.GetDrawObject() ) + { + ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl( + rContext.GetMap()->GetContextImpl( aChild.GetDrawObject(), + &rContext, sal_True ) ); + if( xChildImpl.is() ) + xChild = xChildImpl.get(); + } + return xChild; +} + +// index has to be treated as global child index. +void SwAccessibleSelectionHelper::deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + RuntimeException ) +{ + // return sal_False // we can't deselect + if( nChildIndex < 0 || + nChildIndex >= rContext.GetChildCount( *(rContext.GetMap()) ) ) + throwIndexOutOfBoundsException(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/accselectionhelper.hxx b/sw/source/core/access/accselectionhelper.hxx new file mode 100644 index 000000000000..43ccce61612d --- /dev/null +++ b/sw/source/core/access/accselectionhelper.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCSELECTIONHELPER_HXX_ +#define _ACCSELECTIONHELPER_HXX_ +class SwAccessibleContext; +class SwFEShell; +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> + +class SwAccessibleSelectionHelper +{ + /// the context on which this helper works + SwAccessibleContext& rContext; + + + /// get FE-Shell + SwFEShell* GetFEShell(); + + void throwIndexOutOfBoundsException() + throw ( ::com::sun::star::lang::IndexOutOfBoundsException ); + +public: + + SwAccessibleSelectionHelper( SwAccessibleContext& rContext ); + ~SwAccessibleSelectionHelper(); + + + //===== XAccessibleSelection ============================================ + + void selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + sal_Bool isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + void clearAccessibleSelection( ) + throw ( ::com::sun::star::uno::RuntimeException ); + void selectAllAccessibleChildren( ) + throw ( ::com::sun::star::uno::RuntimeException ); + sal_Int32 getSelectedAccessibleChildCount( ) + throw ( ::com::sun::star::uno::RuntimeException ); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + // index has to be treated as global child index. + void deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acctable.cxx b/sw/source/core/access/acctable.cxx new file mode 100644 index 000000000000..ba843fb22715 --- /dev/null +++ b/sw/source/core/access/acctable.cxx @@ -0,0 +1,1755 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <osl/mutex.hxx> +#include <rtl/uuid.h> +#include <rtl/ustrbuf.hxx> + +#include <list> +#include <set> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> +#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <vcl/svapp.hxx> +#include <frmfmt.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <cellfrm.hxx> +#include <swtable.hxx> +#include <crsrsh.hxx> +#include <viscrs.hxx> +#include <hints.hxx> +#include <fesh.hxx> +#include <accfrmobjslist.hxx> +#include <accmap.hxx> +#include <access.hrc> +#include <acctable.hxx> + +#include <com/sun/star/accessibility/XAccessibleText.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using namespace ::sw::access; + +const sal_Char sServiceName[] = "com.sun.star.table.AccessibleTableView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleTableView"; + +typedef ::std::less < sal_Int32 > Int32Less_Impl; +typedef ::std::set < sal_Int32, Int32Less_Impl > Int32Set_Impl; + +typedef ::std::pair < sal_Int32, sal_Int32 > Int32Pair_Impl; +typedef ::std::list < Int32Pair_Impl > Int32PairList_Impl; + +class SwAccTableSelHander_Impl +{ +public: + virtual void Unselect( sal_Int32 nRowOrCol, sal_Int32 nExt ) = 0; +}; + + +//------------------------------------------------------------------------------ + +class SwAccessibleTableData_Impl +{ + SwAccessibleMap& mrAccMap; + Int32Set_Impl maRows; + Int32Set_Impl maColumns; + Int32PairList_Impl maExtents; // cell extends for event processing only + Point maTabFrmPos; + const SwTabFrm *mpTabFrm; + sal_Bool mbIsInPagePreview; + bool mbOnlyTableColumnHeader; + + void CollectData( const SwFrm *pFrm ); + void CollectExtents( const SwFrm *pFrm ); + + sal_Bool FindCell( const Point& rPos, const SwFrm *pFrm , + sal_Bool bExact, const SwFrm *& rFrm ) const; + + void GetSelection( const Point& rTabPos, const SwRect& rArea, + const SwSelBoxes& rSelBoxes, const SwFrm *pFrm, + SwAccTableSelHander_Impl& rSelHdl, + sal_Bool bColumns ) const; + + // #i77106# + inline bool IncludeRow( const SwFrm& rFrm ) const + { + return !mbOnlyTableColumnHeader || + mpTabFrm->IsInHeadline( rFrm ); + } + // <-- +public: + // #i77106# - add third optional parameter <bOnlyTableColumnHeader>, default value <false> + SwAccessibleTableData_Impl( SwAccessibleMap& rAccMap, + const SwTabFrm *pTabFrm, + sal_Bool bIsInPagePreview, + bool bOnlyTableColumnHeader = false ); + // <-- + + const Int32Set_Impl& GetRows() const { return maRows; } + const Int32Set_Impl& GetColumns() const { return maColumns; } + + inline Int32Set_Impl::const_iterator GetRowIter( sal_Int32 nRow ) const; + inline Int32Set_Impl::const_iterator GetColumnIter( sal_Int32 nCol ) const; + + const SwFrm *GetCell( sal_Int32 nRow, sal_Int32 nColumn, sal_Bool bExact, + SwAccessibleTable *pThis ) const + throw(lang::IndexOutOfBoundsException ); + const SwFrm *GetCellAtPos( sal_Int32 nLeft, sal_Int32 nTop, + sal_Bool bExact ) const; + inline sal_Int32 GetRowCount() const; + inline sal_Int32 GetColumnCount() const; + sal_Bool CompareExtents( const SwAccessibleTableData_Impl& r ) const; + + void GetSelection( sal_Int32 nStart, sal_Int32 nEnd, + const SwSelBoxes& rSelBoxes, + SwAccTableSelHander_Impl& rSelHdl, + sal_Bool bColumns ) const; + + void CheckRowAndCol( sal_Int32 nRow, sal_Int32 nCol, + SwAccessibleTable *pThis ) const + throw(lang::IndexOutOfBoundsException ); + + void GetRowColumnAndExtent( const SwRect& rBox, + sal_Int32& rRow, sal_Int32& rColumn, + sal_Int32& rRowExtent, + sal_Int32& rColumnExtent ) const; + + const Point& GetTablePos() const { return maTabFrmPos; } + void SetTablePos( const Point& rPos ) { maTabFrmPos = rPos; } +}; + +void SwAccessibleTableData_Impl::CollectData( const SwFrm *pFrm ) +{ + const SwAccessibleChildSList aList( *pFrm, mrAccMap ); + SwAccessibleChildSList::const_iterator aIter( aList.begin() ); + SwAccessibleChildSList::const_iterator aEndIter( aList.end() ); + while( aIter != aEndIter ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm *pLower = rLower.GetSwFrm(); + if( pLower ) + { + if( pLower->IsRowFrm() ) + { + // #i77106# + if ( IncludeRow( *pLower ) ) + { + maRows.insert( pLower->Frm().Top() - maTabFrmPos.Y() ); + CollectData( pLower ); + } + } + else if( pLower->IsCellFrm() && + rLower.IsAccessible( mbIsInPagePreview ) ) + { + maColumns.insert( pLower->Frm().Left() - maTabFrmPos.X() ); + } + else + { + CollectData( pLower ); + } + } + ++aIter; + } +} + +void SwAccessibleTableData_Impl::CollectExtents( const SwFrm *pFrm ) +{ + const SwAccessibleChildSList aList( *pFrm, mrAccMap ); + SwAccessibleChildSList::const_iterator aIter( aList.begin() ); + SwAccessibleChildSList::const_iterator aEndIter( aList.end() ); + while( aIter != aEndIter ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm *pLower = rLower.GetSwFrm(); + if( pLower ) + { + if( pLower->IsCellFrm() && + rLower.IsAccessible( mbIsInPagePreview ) ) + { + sal_Int32 nRow, nCol; + Int32Pair_Impl aCellExtents; + GetRowColumnAndExtent( pLower->Frm(), nRow, nCol, + aCellExtents.first, + aCellExtents.second ); + + maExtents.push_back( aCellExtents ); + } + else + { + // #i77106# + if ( !pLower->IsRowFrm() || + IncludeRow( *pLower ) ) + { + CollectExtents( pLower ); + } + } + } + ++aIter; + } +} + +sal_Bool SwAccessibleTableData_Impl::FindCell( + const Point& rPos, const SwFrm *pFrm, sal_Bool bExact, + const SwFrm *& rRet ) const +{ + sal_Bool bFound = sal_False; + + const SwAccessibleChildSList aList( *pFrm, mrAccMap ); + SwAccessibleChildSList::const_iterator aIter( aList.begin() ); + SwAccessibleChildSList::const_iterator aEndIter( aList.end() ); + while( !bFound && aIter != aEndIter ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm *pLower = rLower.GetSwFrm(); + OSL_ENSURE( pLower, "child should be a frame" ); + if( pLower ) + { + if( rLower.IsAccessible( mbIsInPagePreview ) ) + { + OSL_ENSURE( pLower->IsCellFrm(), "lower is not a cell frame" ); + const SwRect& rFrm = pLower->Frm(); + if( rFrm.Right() >= rPos.X() && rFrm.Bottom() >= rPos.Y() ) + { + // We have found the cell + OSL_ENSURE( rFrm.Left() <= rPos.X() && rFrm.Top() <= rPos.Y(), + "find frame moved to far!" ); + bFound = sal_True; + if( !bExact || + (rFrm.Top() == rPos.Y() && rFrm.Left() == rPos.Y() ) ) + { + rRet = pLower; + } + } + } + else + { + // #i77106# + if ( !pLower->IsRowFrm() || + IncludeRow( *pLower ) ) + { + bFound = FindCell( rPos, pLower, bExact, rRet ); + } + } + } + ++aIter; + } + + return bFound; +} + +void SwAccessibleTableData_Impl::GetSelection( + const Point& rTabPos, + const SwRect& rArea, + const SwSelBoxes& rSelBoxes, + const SwFrm *pFrm, + SwAccTableSelHander_Impl& rSelHdl, + sal_Bool bColumns ) const +{ + const SwAccessibleChildSList aList( *pFrm, mrAccMap ); + SwAccessibleChildSList::const_iterator aIter( aList.begin() ); + SwAccessibleChildSList::const_iterator aEndIter( aList.end() ); + while( aIter != aEndIter ) + { + const SwAccessibleChild& rLower = *aIter; + const SwFrm *pLower = rLower.GetSwFrm(); + OSL_ENSURE( pLower, "child should be a frame" ); + const SwRect& rBox = rLower.GetBox( mrAccMap ); + if( pLower && rBox.IsOver( rArea ) ) + { + if( rLower.IsAccessible( mbIsInPagePreview ) ) + { + OSL_ENSURE( pLower->IsCellFrm(), "lower is not a cell frame" ); + const SwCellFrm *pCFrm = + static_cast < const SwCellFrm * >( pLower ); + SwTableBox *pBox = + const_cast< SwTableBox *>( pCFrm->GetTabBox() ); //SVPtrArr! + if( !rSelBoxes.Seek_Entry( pBox ) ) + { + const Int32Set_Impl rRowsOrCols = + bColumns ? maColumns : maRows; + + sal_Int32 nPos = bColumns ? (rBox.Left() - rTabPos.X()) + : (rBox.Top() - rTabPos.Y()); + Int32Set_Impl::const_iterator aSttRowOrCol( + rRowsOrCols.lower_bound( nPos ) ); + sal_Int32 nRowOrCol = + static_cast< sal_Int32 >( ::std::distance( + rRowsOrCols.begin(), aSttRowOrCol ) ); + + nPos = bColumns ? (rBox.Right() - rTabPos.X()) + : (rBox.Bottom() - rTabPos.Y()); + Int32Set_Impl::const_iterator aEndRowOrCol( + rRowsOrCols.upper_bound( nPos ) ); + sal_Int32 nExt = + static_cast< sal_Int32 >( ::std::distance( + aSttRowOrCol, aEndRowOrCol ) ); + + rSelHdl.Unselect( nRowOrCol, nExt ); + } + } + else + { + // #i77106# + if ( !pLower->IsRowFrm() || + IncludeRow( *pLower ) ) + { + GetSelection( rTabPos, rArea, rSelBoxes, pLower, rSelHdl, + bColumns ); + } + } + } + ++aIter; + } +} + +const SwFrm *SwAccessibleTableData_Impl::GetCell( + sal_Int32 nRow, sal_Int32 nColumn, sal_Bool, + SwAccessibleTable *pThis ) const + throw(lang::IndexOutOfBoundsException ) +{ + CheckRowAndCol( nRow, nColumn, pThis ); + + Int32Set_Impl::const_iterator aSttCol( GetColumnIter( nColumn ) ); + Int32Set_Impl::const_iterator aSttRow( GetRowIter( nRow ) ); + const SwFrm *pCellFrm = GetCellAtPos( *aSttCol, *aSttRow, sal_False ); + + return pCellFrm; +} + +void SwAccessibleTableData_Impl::GetSelection( + sal_Int32 nStart, sal_Int32 nEnd, + const SwSelBoxes& rSelBoxes, + SwAccTableSelHander_Impl& rSelHdl, + sal_Bool bColumns ) const +{ + SwRect aArea( mpTabFrm->Frm() ); + Point aPos( aArea.Pos() ); + + const Int32Set_Impl& rRowsOrColumns = bColumns ? maColumns : maRows; + if( nStart > 0 ) + { + Int32Set_Impl::const_iterator aStt( rRowsOrColumns.begin() ); + ::std::advance( aStt, + static_cast< Int32Set_Impl::difference_type >( nStart ) ); + if( bColumns ) + aArea.Left( *aStt + aPos.X() ); + else + aArea.Top( *aStt + aPos.Y() ); + } + if( nEnd < static_cast< sal_Int32 >( rRowsOrColumns.size() ) ) + { + Int32Set_Impl::const_iterator aEnd( rRowsOrColumns.begin() ); + ::std::advance( aEnd, + static_cast< Int32Set_Impl::difference_type >( nEnd ) ); + if( bColumns ) + aArea.Right( *aEnd + aPos.X() - 1 ); + else + aArea.Bottom( *aEnd + aPos.Y() - 1 ); + } + + GetSelection( aPos, aArea, rSelBoxes, mpTabFrm, rSelHdl, bColumns ); +} + +const SwFrm *SwAccessibleTableData_Impl::GetCellAtPos( + sal_Int32 nLeft, sal_Int32 nTop, sal_Bool bExact ) const +{ + Point aPos( mpTabFrm->Frm().Pos() ); + aPos.Move( nLeft, nTop ); + const SwFrm *pRet = 0; + FindCell( aPos, mpTabFrm, bExact, pRet ); + + return pRet; +} + +inline sal_Int32 SwAccessibleTableData_Impl::GetRowCount() const +{ + return static_cast< sal_Int32 >( maRows.size() ); +} + +inline sal_Int32 SwAccessibleTableData_Impl::GetColumnCount() const +{ + return static_cast< sal_Int32 >( maColumns.size() ); +} + +sal_Bool SwAccessibleTableData_Impl::CompareExtents( + const SwAccessibleTableData_Impl& rCmp ) const +{ + if( maExtents.size() != rCmp.maExtents.size() ) + return sal_False; + + Int32PairList_Impl::const_iterator aIter( maExtents.begin() ); + Int32PairList_Impl::const_iterator aEndIter( maExtents.end() ); + Int32PairList_Impl::const_iterator aCmpIter( rCmp.maExtents.begin() ); + while( aIter != aEndIter ) + { + if( *aIter != *aCmpIter ) + return sal_False; + + ++aIter; + ++aCmpIter; + } + + return sal_True; +} + +SwAccessibleTableData_Impl::SwAccessibleTableData_Impl( SwAccessibleMap& rAccMap, + const SwTabFrm *pTabFrm, + sal_Bool bIsInPagePreview, + bool bOnlyTableColumnHeader ) + : mrAccMap( rAccMap ) + , maTabFrmPos( pTabFrm->Frm().Pos() ) + , mpTabFrm( pTabFrm ) + , mbIsInPagePreview( bIsInPagePreview ) + , mbOnlyTableColumnHeader( bOnlyTableColumnHeader ) +{ + CollectData( mpTabFrm ); + CollectExtents( mpTabFrm ); +} + +inline Int32Set_Impl::const_iterator SwAccessibleTableData_Impl::GetRowIter( + sal_Int32 nRow ) const +{ + Int32Set_Impl::const_iterator aCol( GetRows().begin() ); + if( nRow > 0 ) + { + ::std::advance( aCol, + static_cast< Int32Set_Impl::difference_type >( nRow ) ); + } + return aCol; +} + +inline Int32Set_Impl::const_iterator SwAccessibleTableData_Impl::GetColumnIter( + sal_Int32 nColumn ) const +{ + Int32Set_Impl::const_iterator aCol = GetColumns().begin(); + if( nColumn > 0 ) + { + ::std::advance( aCol, + static_cast< Int32Set_Impl::difference_type >( nColumn ) ); + } + return aCol; +} + +void SwAccessibleTableData_Impl::CheckRowAndCol( + sal_Int32 nRow, sal_Int32 nCol, SwAccessibleTable *pThis ) const + throw(lang::IndexOutOfBoundsException ) +{ + if( ( nRow < 0 || nRow >= static_cast< sal_Int32 >( maRows.size() ) ) || + ( nCol < 0 || nCol >= static_cast< sal_Int32 >( maColumns.size() ) ) ) + { + uno::Reference < XAccessibleTable > xThis( pThis ); + lang::IndexOutOfBoundsException aExcept( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "row or column index out of range") ), + xThis ); + throw aExcept; + } +} + +void SwAccessibleTableData_Impl::GetRowColumnAndExtent( + const SwRect& rBox, + sal_Int32& rRow, sal_Int32& rColumn, + sal_Int32& rRowExtent, sal_Int32& rColumnExtent ) const +{ + Int32Set_Impl::const_iterator aStt( + maRows.lower_bound( rBox.Top() - maTabFrmPos.Y() ) ); + Int32Set_Impl::const_iterator aEnd( + maRows.upper_bound( rBox.Bottom() - maTabFrmPos.Y() ) ); + rRow = + static_cast< sal_Int32 >( ::std::distance( maRows.begin(), aStt ) ); + rRowExtent = + static_cast< sal_Int32 >( ::std::distance( aStt, aEnd ) ); + + aStt = maColumns.lower_bound( rBox.Left() - maTabFrmPos.X() ); + aEnd = maColumns.upper_bound( rBox.Right() - maTabFrmPos.X() ); + rColumn = + static_cast< sal_Int32 >( ::std::distance( maColumns.begin(), aStt ) ); + rColumnExtent = + static_cast< sal_Int32 >( ::std::distance( aStt, aEnd ) ); +} + +//------------------------------------------------------------------------------ + +class SwAccSingleTableSelHander_Impl : public SwAccTableSelHander_Impl +{ + sal_Bool bSelected; + +public: + + inline SwAccSingleTableSelHander_Impl(); + + inline sal_Bool IsSelected() const { return bSelected; } + + virtual void Unselect( sal_Int32, sal_Int32 ); +}; + +inline SwAccSingleTableSelHander_Impl::SwAccSingleTableSelHander_Impl() : + bSelected( sal_True ) +{ +} + +void SwAccSingleTableSelHander_Impl::Unselect( sal_Int32, sal_Int32 ) +{ + bSelected = sal_False; +} + +//------------------------------------------------------------------------------ + +class SwAccAllTableSelHander_Impl : public SwAccTableSelHander_Impl + +{ + ::std::vector< sal_Bool > aSelected; + sal_Int32 nCount; + +public: + + inline SwAccAllTableSelHander_Impl( sal_Int32 nSize ); + + uno::Sequence < sal_Int32 > GetSelSequence(); + + virtual void Unselect( sal_Int32 nRowOrCol, sal_Int32 nExt ); + virtual ~SwAccAllTableSelHander_Impl(); +}; + +SwAccAllTableSelHander_Impl::~SwAccAllTableSelHander_Impl() +{ +} + +inline SwAccAllTableSelHander_Impl::SwAccAllTableSelHander_Impl( sal_Int32 nSize ) : + aSelected( nSize, sal_True ), + nCount( nSize ) +{ +} + +uno::Sequence < sal_Int32 > SwAccAllTableSelHander_Impl::GetSelSequence() +{ + OSL_ENSURE( nCount >= 0, "underflow" ); + uno::Sequence < sal_Int32 > aRet( nCount ); + sal_Int32 *pRet = aRet.getArray(); + sal_Int32 nPos = 0; + size_t nSize = aSelected.size(); + for( size_t i=0; i < nSize && nPos < nCount; i++ ) + { + if( aSelected[i] ) + { + *pRet++ = i; + nPos++; + } + } + + OSL_ENSURE( nPos == nCount, "count is wrong" ); + + return aRet; +} + +void SwAccAllTableSelHander_Impl::Unselect( sal_Int32 nRowOrCol, + sal_Int32 nExt ) +{ + OSL_ENSURE( static_cast< size_t >( nRowOrCol ) < aSelected.size(), + "index to large" ); + OSL_ENSURE( static_cast< size_t >( nRowOrCol+nExt ) <= aSelected.size(), + "extent to large" ); + while( nExt ) + { + if( aSelected[static_cast< size_t >( nRowOrCol )] ) + { + aSelected[static_cast< size_t >( nRowOrCol )] = sal_False; + nCount--; + } + nExt--; + nRowOrCol++; + } +} + +//------------------------------------------------------------------------------ + +const SwSelBoxes *SwAccessibleTable::GetSelBoxes() const +{ + const SwSelBoxes *pSelBoxes = 0; + const SwCrsrShell *pCSh = GetCrsrShell(); + if( (pCSh != NULL) && pCSh->IsTableMode() ) + { + pSelBoxes = &pCSh->GetTableCrsr()->GetBoxes(); + } + + return pSelBoxes; +} + +void SwAccessibleTable::FireTableChangeEvent( + const SwAccessibleTableData_Impl& rTableData ) +{ + AccessibleTableModelChange aModelChange; + aModelChange.Type = AccessibleTableModelChangeType::UPDATE; + aModelChange.FirstRow = 0; + aModelChange.LastRow = rTableData.GetRowCount() - 1; + aModelChange.FirstColumn = 0; + aModelChange.LastColumn = rTableData.GetColumnCount() - 1; + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED; + aEvent.NewValue <<= aModelChange; + + FireAccessibleEvent( aEvent ); +} + + +const SwTableBox* SwAccessibleTable::GetTableBox( sal_Int32 nChildIndex ) const +{ + DBG_ASSERT( nChildIndex >= 0, "Illegal child index." ); + DBG_ASSERT( nChildIndex < const_cast<SwAccessibleTable*>(this)->getAccessibleChildCount(), "Illegal child index." ); // #i77106# + + const SwTableBox* pBox = NULL; + + // get table box for 'our' table cell + SwAccessibleChild aCell( GetChild( *(const_cast<SwAccessibleMap*>(GetMap())), nChildIndex ) ); + if( aCell.GetSwFrm() ) + { + const SwFrm* pChildFrm = aCell.GetSwFrm(); + if( (pChildFrm != NULL) && pChildFrm->IsCellFrm() ) + { + const SwCellFrm* pCellFrm = + static_cast<const SwCellFrm*>( pChildFrm ); + pBox = pCellFrm->GetTabBox(); + } + } + + DBG_ASSERT( pBox != NULL, "We need the table box." ); + return pBox; +} + +sal_Bool SwAccessibleTable::IsChildSelected( sal_Int32 nChildIndex ) const +{ + sal_Bool bRet = sal_False; + const SwSelBoxes* pSelBoxes = GetSelBoxes(); + if( pSelBoxes ) + { + const SwTableBox* pBox = GetTableBox( nChildIndex ); + DBG_ASSERT( pBox != NULL, "We need the table box." ); + bRet = pSelBoxes->Seek_Entry( const_cast<SwTableBox*>( pBox ) ); + } + + return bRet; +} + +sal_Int32 SwAccessibleTable::GetIndexOfSelectedChild( + sal_Int32 nSelectedChildIndex ) const +{ + // iterate over all children to n-th isAccessibleChildSelected() + sal_Int32 nChildren = const_cast<SwAccessibleTable*>(this)->getAccessibleChildCount(); // #i77106# + if( nSelectedChildIndex >= nChildren ) + return -1L; + + sal_Int32 n = 0; + while( n < nChildren ) + { + if( IsChildSelected( n ) ) + { + if( 0 == nSelectedChildIndex ) + break; + else + --nSelectedChildIndex; + } + ++n; + } + + return n < nChildren ? n : -1L; +} + +void SwAccessibleTable::GetStates( + ::utl::AccessibleStateSetHelper& rStateSet ) +{ + SwAccessibleContext::GetStates( rStateSet ); + + // MULTISELECTABLE + SwCrsrShell* pCrsrShell = GetCrsrShell(); + if( pCrsrShell ) + rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE ); +} + +SwAccessibleTable::SwAccessibleTable( + SwAccessibleMap* pInitMap, + const SwTabFrm* pTabFrm ) : + SwAccessibleContext( pInitMap, AccessibleRole::TABLE, pTabFrm ), + mpTableData( 0 ) +{ + SolarMutexGuard aGuard; + + const SwFrmFmt *pFrmFmt = pTabFrm->GetFmt(); + const_cast< SwFrmFmt * >( pFrmFmt )->Add( this ); + const String& rName = pFrmFmt->GetName(); + + OUStringBuffer aBuffer( rName.Len() + 4 ); + aBuffer.append( OUString(rName) ); + aBuffer.append( static_cast<sal_Unicode>( '-' ) ); + aBuffer.append( static_cast<sal_Int32>( pTabFrm->GetPhyPageNum() ) ); + + SetName( aBuffer.makeStringAndClear() ); + + OUString sArg1( static_cast< const SwTabFrm * >( GetFrm() ) + ->GetFmt()->GetName() ); + OUString sArg2( GetFormattedPageNumber() ); + + sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sArg1, &sArg2 ); +} + +SwAccessibleTable::~SwAccessibleTable() +{ + SolarMutexGuard aGuard; + + delete mpTableData; +} + +void SwAccessibleTable::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) +{ + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; + const SwTabFrm *pTabFrm = static_cast< const SwTabFrm * >( GetFrm() ); + switch( nWhich ) + { + case RES_NAME_CHANGED: + if( pTabFrm ) + { + const SwFrmFmt *pFrmFmt = pTabFrm->GetFmt(); + OSL_ENSURE( pFrmFmt == GetRegisteredIn(), "invalid frame" ); + + OUString sOldName( GetName() ); + + const String& rNewTabName = pFrmFmt->GetName(); + OUStringBuffer aBuffer( rNewTabName.Len() + 4 ); + aBuffer.append( OUString(rNewTabName) ); + aBuffer.append( static_cast<sal_Unicode>( '-' ) ); + aBuffer.append( static_cast<sal_Int32>( pTabFrm->GetPhyPageNum() ) ); + + SetName( aBuffer.makeStringAndClear() ); + if( sOldName != GetName() ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::NAME_CHANGED; + aEvent.OldValue <<= sOldName; + aEvent.NewValue <<= GetName(); + FireAccessibleEvent( aEvent ); + } + + OUString sOldDesc( sDesc ); + OUString sArg1( rNewTabName ); + OUString sArg2( GetFormattedPageNumber() ); + + sDesc = GetResource( STR_ACCESS_TABLE_DESC, &sArg1, &sArg2 ); + if( sDesc != sOldDesc ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; + aEvent.OldValue <<= sOldDesc; + aEvent.NewValue <<= sDesc; + FireAccessibleEvent( aEvent ); + } + } + break; + + case RES_OBJECTDYING: + // mba: it seems that this class intentionally does not call code in base class SwClient + if( GetRegisteredIn() == + static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) ) + GetRegisteredInNonConst()->Remove( this ); + break; + + default: + // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING + break; + } +} + +uno::Any SwAccessibleTable::queryInterface( const uno::Type& rType ) + throw (uno::RuntimeException) +{ + uno::Any aRet; + if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleTable > * >( 0 ) ) ) + { + uno::Reference<XAccessibleTable> xThis( this ); + aRet <<= xThis; + } + else if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ) ) + { + uno::Reference<XAccessibleSelection> xSelection( this ); + aRet <<= xSelection; + } + else + { + aRet = SwAccessibleContext::queryInterface(rType); + } + + return aRet; +} + +//====== XTypeProvider ==================================================== +uno::Sequence< uno::Type > SAL_CALL SwAccessibleTable::getTypes() + throw(uno::RuntimeException) +{ + uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); + + sal_Int32 nIndex = aTypes.getLength(); + aTypes.realloc( nIndex + 2 ); + + uno::Type* pTypes = aTypes.getArray(); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ); + pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTable > * >( 0 ) ); + + return aTypes; +} + +uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleTable::getImplementationId() + throw(uno::RuntimeException) +{ + SolarMutexGuard aGuard; + static uno::Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + +// #i77106# +SwAccessibleTableData_Impl* SwAccessibleTable::CreateNewTableData() +{ + const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>( GetFrm() ); + return new SwAccessibleTableData_Impl( *GetMap(), pTabFrm, IsInPagePreview() ); +} +// <-- + +void SwAccessibleTable::UpdateTableData() +{ + // #i77106# - usage of new method <CreateNewTableData()> + delete mpTableData; + mpTableData = CreateNewTableData(); + // <-- +} + +void SwAccessibleTable::ClearTableData() +{ + delete mpTableData; + mpTableData = 0; +} + +OUString SAL_CALL SwAccessibleTable::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + return sDesc; +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowCount() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + return GetTableData().GetRowCount(); +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnCount( ) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + return GetTableData().GetColumnCount(); +} + +OUString SAL_CALL SwAccessibleTable::getAccessibleRowDescription( + sal_Int32 nRow ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // #i87532# - determine table cell in <nRow>th row and + // in first column of row header table and return its text content. + OUString sRowDesc; + + GetTableData().CheckRowAndCol(nRow, 0, this); + + uno::Reference< XAccessibleTable > xTableRowHeader = getAccessibleRowHeaders(); + if ( xTableRowHeader.is() ) + { + uno::Reference< XAccessible > xRowHeaderCell = + xTableRowHeader->getAccessibleCellAt( nRow, 0 ); + OSL_ENSURE( xRowHeaderCell.is(), + "<SwAccessibleTable::getAccessibleRowDescription(..)> - missing row header cell -> serious issue." ); + uno::Reference< XAccessibleContext > xRowHeaderCellContext = + xRowHeaderCell->getAccessibleContext(); + const sal_Int32 nCellChildCount( xRowHeaderCellContext->getAccessibleChildCount() ); + for ( sal_Int32 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex ) + { + uno::Reference< XAccessible > xChild = xRowHeaderCellContext->getAccessibleChild( nChildIndex ); + uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY ); + if ( xChildText.is() ) + { + sRowDesc = sRowDesc + xChildText->getText(); + } + } + } + + return sRowDesc; + // <-- +} + +OUString SAL_CALL SwAccessibleTable::getAccessibleColumnDescription( + sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // #i87532# - determine table cell in first row and + // in <nColumn>th column of column header table and return its text content. + OUString sColumnDesc; + + GetTableData().CheckRowAndCol(0, nColumn, this); + + uno::Reference< XAccessibleTable > xTableColumnHeader = getAccessibleColumnHeaders(); + if ( xTableColumnHeader.is() ) + { + uno::Reference< XAccessible > xColumnHeaderCell = + xTableColumnHeader->getAccessibleCellAt( 0, nColumn ); + OSL_ENSURE( xColumnHeaderCell.is(), + "<SwAccessibleTable::getAccessibleColumnDescription(..)> - missing column header cell -> serious issue." ); + uno::Reference< XAccessibleContext > xColumnHeaderCellContext = + xColumnHeaderCell->getAccessibleContext(); + const sal_Int32 nCellChildCount( xColumnHeaderCellContext->getAccessibleChildCount() ); + for ( sal_Int32 nChildIndex = 0; nChildIndex < nCellChildCount; ++nChildIndex ) + { + uno::Reference< XAccessible > xChild = xColumnHeaderCellContext->getAccessibleChild( nChildIndex ); + uno::Reference< XAccessibleText > xChildText( xChild, uno::UNO_QUERY ); + if ( xChildText.is() ) + { + sColumnDesc = sColumnDesc + xChildText->getText(); + } + } + } + + return sColumnDesc; + // <-- +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRowExtentAt( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + sal_Int32 nExtend = -1; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + GetTableData().CheckRowAndCol( nRow, nColumn, this ); + + Int32Set_Impl::const_iterator aSttCol( + GetTableData().GetColumnIter( nColumn ) ); + Int32Set_Impl::const_iterator aSttRow( + GetTableData().GetRowIter( nRow ) ); + const SwFrm *pCellFrm = GetTableData().GetCellAtPos( *aSttCol, *aSttRow, + sal_False ); + if( pCellFrm ) + { + sal_Int32 nBottom = pCellFrm->Frm().Bottom(); + nBottom -= GetFrm()->Frm().Top(); + Int32Set_Impl::const_iterator aEndRow( + GetTableData().GetRows().upper_bound( nBottom ) ); + nExtend = + static_cast< sal_Int32 >( ::std::distance( aSttRow, aEndRow ) ); + } + + return nExtend; +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumnExtentAt( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + sal_Int32 nExtend = -1; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + GetTableData().CheckRowAndCol( nRow, nColumn, this ); + + Int32Set_Impl::const_iterator aSttCol( + GetTableData().GetColumnIter( nColumn ) ); + Int32Set_Impl::const_iterator aSttRow( + GetTableData().GetRowIter( nRow ) ); + const SwFrm *pCellFrm = GetTableData().GetCellAtPos( *aSttCol, *aSttRow, + sal_False ); + if( pCellFrm ) + { + sal_Int32 nRight = pCellFrm->Frm().Right(); + nRight -= GetFrm()->Frm().Left(); + Int32Set_Impl::const_iterator aEndCol( + GetTableData().GetColumns().upper_bound( nRight ) ); + nExtend = + static_cast< sal_Int32 >( ::std::distance( aSttCol, aEndCol ) ); + } + + return nExtend; +} + +uno::Reference< XAccessibleTable > SAL_CALL + SwAccessibleTable::getAccessibleRowHeaders( ) + throw (uno::RuntimeException) +{ + // Row headers aren't supported + return uno::Reference< XAccessibleTable >(); +} + +uno::Reference< XAccessibleTable > SAL_CALL + SwAccessibleTable::getAccessibleColumnHeaders( ) + throw (uno::RuntimeException) +{ + // #i87532# - assure that return accesible object is empty, + // if no column header exists. + SwAccessibleTableColHeaders* pTableColHeaders = + new SwAccessibleTableColHeaders( GetMap(), static_cast< const SwTabFrm *>( GetFrm() ) ); + uno::Reference< XAccessibleTable > xTableColumnHeaders( pTableColHeaders ); + if ( pTableColHeaders->getAccessibleChildCount() <= 0 ) + { + return uno::Reference< XAccessibleTable >(); + } + + return xTableColumnHeaders; + // <-- +} + +uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleRows() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + const SwSelBoxes *pSelBoxes = GetSelBoxes(); + if( pSelBoxes ) + { + sal_Int32 nRows = GetTableData().GetRowCount(); + SwAccAllTableSelHander_Impl aSelRows( nRows ); + + GetTableData().GetSelection( 0, nRows, *pSelBoxes, aSelRows, + sal_False ); + + return aSelRows.GetSelSequence(); + } + else + { + return uno::Sequence< sal_Int32 >( 0 ); + } +} + +uno::Sequence< sal_Int32 > SAL_CALL SwAccessibleTable::getSelectedAccessibleColumns() + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + const SwSelBoxes *pSelBoxes = GetSelBoxes(); + if( pSelBoxes ) + { + sal_Int32 nCols = GetTableData().GetColumnCount(); + SwAccAllTableSelHander_Impl aSelCols( nCols ); + + GetTableData().GetSelection( 0, nCols, *pSelBoxes, aSelCols, sal_True ); + + return aSelCols.GetSelSequence(); + } + else + { + return uno::Sequence< sal_Int32 >( 0 ); + } +} + +sal_Bool SAL_CALL SwAccessibleTable::isAccessibleRowSelected( sal_Int32 nRow ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + GetTableData().CheckRowAndCol( nRow, 0, this ); + + sal_Bool bRet; + const SwSelBoxes *pSelBoxes = GetSelBoxes(); + if( pSelBoxes ) + { + SwAccSingleTableSelHander_Impl aSelRow; + GetTableData().GetSelection( nRow, nRow+1, *pSelBoxes, aSelRow, + sal_False ); + bRet = aSelRow.IsSelected(); + } + else + { + bRet = sal_False; + } + + return bRet; +} + +sal_Bool SAL_CALL SwAccessibleTable::isAccessibleColumnSelected( + sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + GetTableData().CheckRowAndCol( 0, nColumn, this ); + + sal_Bool bRet; + const SwSelBoxes *pSelBoxes = GetSelBoxes(); + if( pSelBoxes ) + { + SwAccSingleTableSelHander_Impl aSelCol; + + GetTableData().GetSelection( nColumn, nColumn+1, *pSelBoxes, aSelCol, + sal_True ); + bRet = aSelCol.IsSelected(); + } + else + { + bRet = sal_False; + } + + return bRet; +} + +uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCellAt( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + uno::Reference< XAccessible > xRet; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + const SwFrm *pCellFrm = + GetTableData().GetCell( nRow, nColumn, sal_False, this ); + if( pCellFrm ) + xRet = GetMap()->GetContext( pCellFrm, sal_True ); + + return xRet; +} + +uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleCaption() + throw (uno::RuntimeException) +{ + // captions aren't supported + return uno::Reference< XAccessible >(); +} + +uno::Reference< XAccessible > SAL_CALL SwAccessibleTable::getAccessibleSummary() + throw (uno::RuntimeException) +{ + // summaries aren't supported + return uno::Reference< XAccessible >(); +} + +sal_Bool SAL_CALL SwAccessibleTable::isAccessibleSelected( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + sal_Bool bRet = sal_False; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + const SwFrm *pFrm = + GetTableData().GetCell( nRow, nColumn, sal_False, this ); + if( pFrm && pFrm->IsCellFrm() ) + { + const SwSelBoxes *pSelBoxes = GetSelBoxes(); + if( pSelBoxes ) + { + const SwCellFrm *pCFrm = static_cast < const SwCellFrm * >( pFrm ); + SwTableBox *pBox = + const_cast< SwTableBox *>( pCFrm->GetTabBox() ); //SVPtrArr! + bRet = pSelBoxes->Seek_Entry( pBox ); + } + } + + return bRet; +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleIndex( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + sal_Int32 nRet = -1; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + SwAccessibleChild aCell( GetTableData().GetCell( nRow, nColumn, sal_False, this )); + if ( aCell.IsValid() ) + { + nRet = GetChildIndex( *(GetMap()), aCell ); + } + + return nRet; +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleRow( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + sal_Int32 nRet = -1; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + // #i77106# + if ( ( nChildIndex < 0 ) || + ( nChildIndex >= getAccessibleChildCount() ) ) + { + throw lang::IndexOutOfBoundsException(); + } + // <-- + + SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) ); + if ( aCell.GetSwFrm() ) + { + sal_Int32 nTop = aCell.GetSwFrm()->Frm().Top(); + nTop -= GetFrm()->Frm().Top(); + Int32Set_Impl::const_iterator aRow( + GetTableData().GetRows().lower_bound( nTop ) ); + nRet = static_cast< sal_Int32 >( ::std::distance( + GetTableData().GetRows().begin(), aRow ) ); + } + else + { + OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:" + "aCell not expected to be valid."); + + throw lang::IndexOutOfBoundsException(); + } + + return nRet; +} + +sal_Int32 SAL_CALL SwAccessibleTable::getAccessibleColumn( + sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + sal_Int32 nRet = -1; + + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ) + + // #i77106# + if ( ( nChildIndex < 0 ) || + ( nChildIndex >= getAccessibleChildCount() ) ) + { + throw lang::IndexOutOfBoundsException(); + } + // <-- + + SwAccessibleChild aCell( GetChild( *(GetMap()), nChildIndex ) ); + if ( aCell.GetSwFrm() ) + { + sal_Int32 nLeft = aCell.GetSwFrm()->Frm().Left(); + nLeft -= GetFrm()->Frm().Left(); + Int32Set_Impl::const_iterator aCol( + GetTableData().GetColumns().lower_bound( nLeft ) ); + nRet = static_cast< sal_Int32 >( ::std::distance( + GetTableData().GetColumns().begin(), aCol ) ); + } + else + { + OSL_ENSURE( !aCell.IsValid(), "SwAccessibleTable::getAccessibleColumn:" + "aCell not expected to be valid."); + + throw lang::IndexOutOfBoundsException(); + } + + return nRet; +} + + +OUString SAL_CALL SwAccessibleTable::getImplementationName() + throw( uno::RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleTable::supportsService( + const OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +uno::Sequence< OUString > SAL_CALL SwAccessibleTable::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +void SwAccessibleTable::InvalidatePosOrSize( const SwRect& rOldBox ) +{ + SolarMutexGuard aGuard; + + if( HasTableData() ) + GetTableData().SetTablePos( GetFrm()->Frm().Pos() ); + + SwAccessibleContext::InvalidatePosOrSize( rOldBox ); +} + +void SwAccessibleTable::Dispose( sal_Bool bRecursive ) +{ + SolarMutexGuard aGuard; + + if( GetRegisteredIn() ) + GetRegisteredInNonConst()->Remove( this ); + + SwAccessibleContext::Dispose( bRecursive ); +} + +void SwAccessibleTable::DisposeChild( const SwAccessibleChild& rChildFrmOrObj, + sal_Bool bRecursive ) +{ + SolarMutexGuard aGuard; + + const SwFrm *pFrm = rChildFrmOrObj.GetSwFrm(); + OSL_ENSURE( pFrm, "frame expected" ); + if( HasTableData() ) + { + FireTableChangeEvent( GetTableData() ); + ClearTableData(); + } + + // There are two reason why this method has been called. The first one + // is there is no context for pFrm. The method is them called by + // the map, and we have to call our superclass. + // The other situation is that we have been call by a call to get notified + // about its change. We then must not call the superclass + uno::Reference< XAccessible > xAcc( GetMap()->GetContext( pFrm, sal_False ) ); + if( !xAcc.is() ) + SwAccessibleContext::DisposeChild( rChildFrmOrObj, bRecursive ); +} + +void SwAccessibleTable::InvalidateChildPosOrSize( const SwAccessibleChild& rChildFrmOrObj, + const SwRect& rOldBox ) +{ + SolarMutexGuard aGuard; + + if( HasTableData() ) + { + OSL_ENSURE( !HasTableData() || + GetFrm()->Frm().Pos() == GetTableData().GetTablePos(), + "table has invalid position" ); + if( HasTableData() ) + { + SwAccessibleTableData_Impl *pNewTableData = CreateNewTableData(); // #i77106# + if( !pNewTableData->CompareExtents( GetTableData() ) ) + { + FireTableChangeEvent( GetTableData() ); + ClearTableData(); + mpTableData = pNewTableData; + } + else + { + delete pNewTableData; + } + } + } + + // #i013961# - always call super class method + SwAccessibleContext::InvalidateChildPosOrSize( rChildFrmOrObj, rOldBox ); +} + + +// +// XAccessibleSelection +// + +void SAL_CALL SwAccessibleTable::selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleTable ); + + if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106# + throw lang::IndexOutOfBoundsException(); + + // preliminaries: get 'our' table box, and get the cursor shell + const SwTableBox* pBox = GetTableBox( nChildIndex ); + DBG_ASSERT( pBox != NULL, "We need the table box." ); + + SwCrsrShell* pCrsrShell = GetCrsrShell(); + if( pCrsrShell == NULL ) + return; + + // assure, that child, indentified by the given index, isn't already selected. + if ( IsChildSelected( nChildIndex ) ) + { + return; + } + + // now we can start to do the work: check whether we already have + // a table selection (in 'our' table). If so, extend the + // selection, else select the current cell. + + // if we have a selection in a table, check if it's in the + // same table that we're trying to select in + const SwTableNode* pSelectedTable = pCrsrShell->IsCrsrInTbl(); + if( pSelectedTable != NULL ) + { + // get top-most table line + const SwTableLine* pUpper = pBox->GetUpper(); + while( pUpper->GetUpper() != NULL ) + pUpper = pUpper->GetUpper()->GetUpper(); + sal_uInt16 nPos = + pSelectedTable->GetTable().GetTabLines().GetPos( pUpper ); + if( nPos == USHRT_MAX ) + pSelectedTable = NULL; + } + + // create the new selection + const SwStartNode* pStartNode = pBox->GetSttNd(); + if( pSelectedTable == NULL || !pCrsrShell->GetTblCrs() ) + { + pCrsrShell->StartAction(); + // Set cursor into current cell. This deletes any table cursor. + SwPaM aPaM( *pStartNode ); + aPaM.Move( fnMoveForward, fnGoNode ); + Select( aPaM ); + // Move cursor to the end of the table creating a selection and a table + // cursor. + pCrsrShell->SetMark(); + pCrsrShell->MoveTable( fnTableCurr, fnTableEnd ); + // now set the cursor into the cell again. + SwPaM *pPaM = pCrsrShell->GetTblCrs() ? pCrsrShell->GetTblCrs() + : pCrsrShell->GetCrsr(); + *pPaM->GetPoint() = *pPaM->GetMark(); + pCrsrShell->EndAction(); + // we now have one cell selected! + } + else + { + // if the cursor is already in this table, + // expand the current selection (i.e., set + // point to new position; keep mark) + SwPaM aPaM( *pStartNode ); + aPaM.Move( fnMoveForward, fnGoNode ); + aPaM.SetMark(); + const SwPaM *pPaM = pCrsrShell->GetTblCrs() ? pCrsrShell->GetTblCrs() + : pCrsrShell->GetCrsr(); + *(aPaM.GetMark()) = *pPaM->GetMark(); + Select( aPaM ); + + } +} + + +sal_Bool SAL_CALL SwAccessibleTable::isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleTable ); + + if( (nChildIndex < 0) || (nChildIndex >= getAccessibleChildCount()) ) // #i77106# + throw lang::IndexOutOfBoundsException(); + + return IsChildSelected( nChildIndex ); +} + +void SAL_CALL SwAccessibleTable::clearAccessibleSelection( ) + throw ( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleTable ); + + SwCrsrShell* pCrsrShell = GetCrsrShell(); + if( pCrsrShell != NULL ) + { + pCrsrShell->StartAction(); + pCrsrShell->ClearMark(); + pCrsrShell->EndAction(); + } +} + +void SAL_CALL SwAccessibleTable::selectAllAccessibleChildren( ) + throw ( uno::RuntimeException ) +{ + // first clear selection, then select first and last child + clearAccessibleSelection(); + selectAccessibleChild( 0 ); + selectAccessibleChild( getAccessibleChildCount()-1 ); // #i77106# +} + +sal_Int32 SAL_CALL SwAccessibleTable::getSelectedAccessibleChildCount( ) + throw ( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleTable ); + + // iterate over all children and count isAccessibleChildSelected() + sal_Int32 nCount = 0; + + sal_Int32 nChildren = getAccessibleChildCount(); // #i71106# + for( sal_Int32 n = 0; n < nChildren; n++ ) + if( IsChildSelected( n ) ) + nCount++; + + return nCount; +} + +uno::Reference<XAccessible> SAL_CALL SwAccessibleTable::getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleTable ); + + // paremter checking (part 1): index lower 0 + if( nSelectedChildIndex < 0 ) + throw lang::IndexOutOfBoundsException(); + + sal_Int32 nChildIndex = GetIndexOfSelectedChild( nSelectedChildIndex ); + + // parameter checking (part 2): index higher than selected children? + if( nChildIndex < 0 ) + throw lang::IndexOutOfBoundsException(); + + // #i77106# + if ( nChildIndex >= getAccessibleChildCount() ) + { + throw lang::IndexOutOfBoundsException(); + } + + return getAccessibleChild( nChildIndex ); +} + +// index has to be treated as global child index. +void SAL_CALL SwAccessibleTable::deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( lang::IndexOutOfBoundsException, + uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleTable ); + + SwCrsrShell* pCrsrShell = GetCrsrShell(); + + // index has to be treated as global child index + if ( !pCrsrShell ) + throw lang::IndexOutOfBoundsException(); + + // assure, that given child index is in bounds. + if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) // #i77106# + throw lang::IndexOutOfBoundsException(); + + // assure, that child, identified by the given index, is selected. + if ( !IsChildSelected( nChildIndex ) ) + return; + // <-- + + const SwTableBox* pBox = GetTableBox( nChildIndex ); + DBG_ASSERT( pBox != NULL, "We need the table box." ); + + // If we unselect point, then set cursor to mark. If we clear another + // selected box, then set cursor to point. + // reduce selection to mark. + SwPaM *pPaM = pCrsrShell->GetTblCrs() ? pCrsrShell->GetTblCrs() + : pCrsrShell->GetCrsr(); + sal_Bool bDeselectPoint = + pBox->GetSttNd() == + pPaM->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); + + SwPaM aPaM( bDeselectPoint ? *pPaM->GetMark() : *pPaM->GetPoint() ); + + pCrsrShell->StartAction(); + + // Set cursor into either point or mark + Select( aPaM ); + // Move cursor to the end of the table creating a selection and a table + // cursor. + pCrsrShell->SetMark(); + pCrsrShell->MoveTable( fnTableCurr, fnTableEnd ); + // now set the cursor into the cell again. + pPaM = pCrsrShell->GetTblCrs() ? pCrsrShell->GetTblCrs() + : pCrsrShell->GetCrsr(); + *pPaM->GetPoint() = *pPaM->GetMark(); + pCrsrShell->EndAction(); +} + +// #i77106# - implementation of class <SwAccessibleTableColHeaders> +SwAccessibleTableColHeaders::SwAccessibleTableColHeaders( SwAccessibleMap *pMap2, + const SwTabFrm *pTabFrm ) + : SwAccessibleTable( pMap2, pTabFrm ) +{ + SolarMutexGuard aGuard; + + const SwFrmFmt *pFrmFmt = pTabFrm->GetFmt(); + const_cast< SwFrmFmt * >( pFrmFmt )->Add( this ); + const String& rName = pFrmFmt->GetName(); + + OUStringBuffer aBuffer( rName.Len() + 15 + 6 ); + aBuffer.append( OUString(rName) ); + aBuffer.append( String::CreateFromAscii("-ColumnHeaders-") ); + aBuffer.append( static_cast<sal_Int32>( pTabFrm->GetPhyPageNum() ) ); + + SetName( aBuffer.makeStringAndClear() ); + + OUStringBuffer aBuffer2( rName.Len() + 14 ); + aBuffer2.append( OUString(rName) ); + aBuffer2.append( String::CreateFromAscii("-ColumnHeaders") ); + OUString sArg1( aBuffer2.makeStringAndClear() ); + OUString sArg2( GetFormattedPageNumber() ); + + OUString sDesc2 = GetResource( STR_ACCESS_TABLE_DESC, &sArg1, &sArg2 ); + SetDesc( sDesc2 ); + + NotRegisteredAtAccessibleMap(); // #i85634# +} + +SwAccessibleTableData_Impl* SwAccessibleTableColHeaders::CreateNewTableData() +{ + const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>( GetFrm() ); + return new SwAccessibleTableData_Impl( *(GetMap()), pTabFrm, IsInPagePreview(), true ); +} + + +void SwAccessibleTableColHeaders::Modify( const SfxPoolItem * /*pOld*/, const SfxPoolItem * /*pNew*/ ) +{ +} + +//===== XInterface ====================================================== +uno::Any SAL_CALL SwAccessibleTableColHeaders::queryInterface( const uno::Type& aType ) + throw (uno::RuntimeException) +{ + return SwAccessibleTable::queryInterface( aType ); +} + +//===== XAccessibleContext ============================================== +sal_Int32 SAL_CALL SwAccessibleTableColHeaders::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + sal_Int32 nCount = 0; + + const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>( GetFrm() ); + const SwAccessibleChildSList aVisList( GetVisArea(), *pTabFrm, *(GetMap()) ); + SwAccessibleChildSList::const_iterator aIter( aVisList.begin() ); + while( aIter != aVisList.end() ) + { + const SwAccessibleChild& rLower = *aIter; + if( rLower.IsAccessible( IsInPagePreview() ) ) + { + nCount++; + } + else if( rLower.GetSwFrm() ) + { + // There are no unaccessible SdrObjects that count + if ( !rLower.GetSwFrm()->IsRowFrm() || + pTabFrm->IsInHeadline( *(rLower.GetSwFrm()) ) ) + { + nCount += SwAccessibleFrame::GetChildCount( *(GetMap()), + GetVisArea(), + rLower.GetSwFrm(), + IsInPagePreview() ); + } + } + ++aIter; + } + + return nCount; +} + +uno::Reference< XAccessible> SAL_CALL + SwAccessibleTableColHeaders::getAccessibleChild (sal_Int32 nIndex) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + if ( nIndex < 0 || nIndex >= getAccessibleChildCount() ) + { + throw lang::IndexOutOfBoundsException(); + } + + return SwAccessibleTable::getAccessibleChild( nIndex ); +} + +//===== XAccessibleTable ================================================ +uno::Reference< XAccessibleTable > + SAL_CALL SwAccessibleTableColHeaders::getAccessibleRowHeaders() + throw (uno::RuntimeException) +{ + return uno::Reference< XAccessibleTable >(); +} + +uno::Reference< XAccessibleTable > + SAL_CALL SwAccessibleTableColHeaders::getAccessibleColumnHeaders() + throw (uno::RuntimeException) +{ + return uno::Reference< XAccessibleTable >(); +} + +//===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL SwAccessibleTableColHeaders::getImplementationName (void) + throw (uno::RuntimeException) +{ + static const sal_Char sImplName[] = "com.sun.star.comp.Writer.SwAccessibleTableColumnHeadersView"; + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplName)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acctable.hxx b/sw/source/core/access/acctable.hxx new file mode 100644 index 000000000000..491ba5c4416d --- /dev/null +++ b/sw/source/core/access/acctable.hxx @@ -0,0 +1,331 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCTABLE_HXX +#define _ACCTABLE_HXX +#include <com/sun/star/accessibility/XAccessibleTable.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> + +#include <acccontext.hxx> + +class SwTabFrm; +class SwAccessibleTableData_Impl; +class SwTableBox; +class SwSelBoxes; + +namespace sw { namespace access { + class SwAccessibleChild; +} } + +class SwAccessibleTable : + public SwAccessibleContext, + public ::com::sun::star::accessibility::XAccessibleTable, + public ::com::sun::star::accessibility::XAccessibleSelection, + public SwClient +{ + SwAccessibleTableData_Impl *mpTableData; // the table's data, prot by Sol-Mutex + ::rtl::OUString sDesc; + const SwSelBoxes *GetSelBoxes() const; + + void FireTableChangeEvent( const SwAccessibleTableData_Impl& rTableData ); + + /** get the SwTableBox* for the given child */ + const SwTableBox* GetTableBox( sal_Int32 ) const; + + sal_Bool IsChildSelected( sal_Int32 nChildIndex ) const; + + sal_Int32 GetIndexOfSelectedChild( sal_Int32 nSelectedChildIndex ) const; + +protected: + + // Set states for getAccessibleStateSet. + // This drived class additinaly sets MULTISELECTABLE(+) + virtual void GetStates( ::utl::AccessibleStateSetHelper& rStateSet ); + + virtual ~SwAccessibleTable(); + + // #i77106# + inline void SetDesc( ::rtl::OUString sNewDesc ) + { + sDesc = sNewDesc; + } + + virtual SwAccessibleTableData_Impl* CreateNewTableData(); // #i77106# + + // force update of table data + void UpdateTableData(); + + // remove the current table data + void ClearTableData(); + + // get table data, update if necessary + inline SwAccessibleTableData_Impl& GetTableData(); + + // Is table data evailable? + sal_Bool HasTableData() const { return (mpTableData != 0); } + + virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); + +public: + + SwAccessibleTable( SwAccessibleMap* pInitMap, const SwTabFrm* pTableFrm ); + + //===== XInterface ====================================================== + + // (XInterface methods need to be implemented to disambigouate + // between those inherited through SwAcessibleContext and + // XAccessibleTable). + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire( ) throw () + { SwAccessibleContext::acquire(); }; + + virtual void SAL_CALL release( ) throw () + { SwAccessibleContext::release(); }; + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + //===== XAccessibleContext ============================================== + + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + //===== XAccessibleTable ================================================ + + virtual sal_Int32 SAL_CALL getAccessibleRowCount() + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleColumnCount( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleRowDescription( + sal_Int32 nRow ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleColumnDescription( + sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleRowExtentAt( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleColumnExtentAt( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleTable > + SAL_CALL getAccessibleRowHeaders( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleTable > + SAL_CALL getAccessibleColumnHeaders( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL + getSelectedAccessibleRows( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL + getSelectedAccessibleColumns( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAccessibleRowSelected( sal_Int32 nRow ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAccessibleColumnSelected( sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > SAL_CALL + getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > SAL_CALL + getAccessibleCaption( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > SAL_CALL + getAccessibleSummary( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAccessibleSelected( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndex( + sal_Int32 nRow, sal_Int32 nColumn ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleRow( sal_Int32 nChildIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleColumn( sal_Int32 nChildIndex ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //===== C++ interface ====================================================== + + // The object has been moved by the layout + virtual void InvalidatePosOrSize( const SwRect& rOldBox ); + + // The object is not visible an longer and should be destroyed + virtual void Dispose( sal_Bool bRecursive = sal_False ); + + virtual void DisposeChild( const sw::access::SwAccessibleChild& rFrmOrObj, + sal_Bool bRecursive ); + virtual void InvalidateChildPosOrSize( const sw::access::SwAccessibleChild& rFrmOrObj, + const SwRect& rFrm ); + + //===== XAccessibleSelection ============================================ + + virtual void SAL_CALL selectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Bool SAL_CALL isAccessibleChildSelected( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL clearAccessibleSelection( ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL selectAllAccessibleChildren( ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) + throw ( ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( + sal_Int32 nSelectedChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException); + + // index has to be treated as global child index. + virtual void SAL_CALL deselectAccessibleChild( + sal_Int32 nChildIndex ) + throw ( ::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::uno::RuntimeException ); + +}; + +inline SwAccessibleTableData_Impl& SwAccessibleTable::GetTableData() +{ + if( !mpTableData ) + UpdateTableData(); + return *mpTableData; +} + +// #i77106# - subclass to represent table column headers +class SwAccessibleTableColHeaders : public SwAccessibleTable +{ +protected: + + virtual ~SwAccessibleTableColHeaders() + {} + + virtual SwAccessibleTableData_Impl* CreateNewTableData(); + virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); + +public: + + SwAccessibleTableColHeaders( SwAccessibleMap *pMap, const SwTabFrm *pTabFrm ); + + //===== XInterface ====================================================== + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire( ) throw () + { SwAccessibleContext::acquire(); }; + + virtual void SAL_CALL release( ) throw () + { SwAccessibleContext::release(); }; + + //===== XAccessibleContext ============================================== + + /// Return the number of currently visible children. + virtual sal_Int32 SAL_CALL getAccessibleChildCount (void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the specified child or NULL if index is invalid. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleChild (sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IndexOutOfBoundsException); + + //===== XAccessibleTable ================================================ + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleTable > + SAL_CALL getAccessibleRowHeaders( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleTable > + SAL_CALL getAccessibleColumnHeaders( ) + throw (::com::sun::star::uno::RuntimeException); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + +}; +// <-- +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acctextframe.cxx b/sw/source/core/access/acctextframe.cxx new file mode 100644 index 000000000000..6d41322a7703 --- /dev/null +++ b/sw/source/core/access/acctextframe.cxx @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <rtl/uuid.h> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRelation.hpp> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <unotools/accessiblestatesethelper.hxx> +#include <frmfmt.hxx> +#include <flyfrm.hxx> +#include <accmap.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <hints.hxx> // #i73249# +#include "acctextframe.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::rtl::OUString; + +using utl::AccessibleRelationSetHelper; +using ::com::sun::star::accessibility::XAccessibleContext; + +const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextFrameView"; +const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleTextFrameView"; + +SwAccessibleTextFrame::SwAccessibleTextFrame( + SwAccessibleMap* pInitMap, + const SwFlyFrm* pFlyFrm ) : + SwAccessibleFrameBase( pInitMap, AccessibleRole::TEXT_FRAME, pFlyFrm ), + msTitle(), + msDesc() +{ + if ( pFlyFrm ) + { + const SwFlyFrmFmt* pFlyFrmFmt = + dynamic_cast<const SwFlyFrmFmt*>( pFlyFrm->GetFmt() ); + msTitle = pFlyFrmFmt->GetObjTitle(); + + msDesc = pFlyFrmFmt->GetObjDescription(); + if ( msDesc.getLength() == 0 && + msTitle != GetName() ) + { + msDesc = msTitle; + } + } +} + +SwAccessibleTextFrame::~SwAccessibleTextFrame() +{ +} + +void SwAccessibleTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) +{ + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; + // #i73249# - suppress handling of RES_NAME_CHANGED + // in case that attribute Title is used as the accessible name. + if ( nWhich != RES_NAME_CHANGED || + msTitle.getLength() == 0 ) + { + SwAccessibleFrameBase::Modify( pOld, pNew ); + } + + const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() ); + switch( nWhich ) + { + // #i73249# + case RES_TITLE_CHANGED: + { + const String& sOldTitle( + dynamic_cast<const SwStringMsgPoolItem*>(pOld)->GetString() ); + const String& sNewTitle( + dynamic_cast<const SwStringMsgPoolItem*>(pNew)->GetString() ); + if ( sOldTitle == sNewTitle ) + { + break; + } + msTitle = sNewTitle; + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::NAME_CHANGED; + aEvent.OldValue <<= OUString( sOldTitle ); + aEvent.NewValue <<= msTitle; + FireAccessibleEvent( aEvent ); + + const SwFlyFrmFmt* pFlyFrmFmt = + dynamic_cast<const SwFlyFrmFmt*>( pFlyFrm->GetFmt() ); + if ( pFlyFrmFmt->GetObjDescription().Len() != 0 ) + { + break; + } + } + // intentional no break here + case RES_DESCRIPTION_CHANGED: + { + if ( pFlyFrm ) + { + const OUString sOldDesc( msDesc ); + + const SwFlyFrmFmt* pFlyFrmFmt = + dynamic_cast<const SwFlyFrmFmt*>( pFlyFrm->GetFmt() ); + const String& rDesc = pFlyFrmFmt->GetObjDescription(); + msDesc = rDesc; + if ( msDesc.getLength() == 0 && + msTitle != GetName() ) + { + msDesc = msTitle; + } + + if ( msDesc != sOldDesc ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; + aEvent.OldValue <<= sOldDesc; + aEvent.NewValue <<= msDesc; + FireAccessibleEvent( aEvent ); + } + } + } + break; + // <-- + } +} + +// #i73249# +OUString SAL_CALL SwAccessibleTextFrame::getAccessibleName (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + if ( msTitle.getLength() != 0 ) + { + return msTitle; + } + + return SwAccessibleFrameBase::getAccessibleName(); +} +// <-- +OUString SAL_CALL SwAccessibleTextFrame::getAccessibleDescription (void) + throw (uno::RuntimeException) +{ + SolarMutexGuard aGuard; + + CHECK_FOR_DEFUNC( XAccessibleContext ) + + return msDesc; + +} + +OUString SAL_CALL SwAccessibleTextFrame::getImplementationName() + throw( uno::RuntimeException ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); +} + +sal_Bool SAL_CALL SwAccessibleTextFrame::supportsService( + const OUString& sTestServiceName) + throw (uno::RuntimeException) +{ + return sTestServiceName.equalsAsciiL( sServiceName, + sizeof(sServiceName)-1 ) || + sTestServiceName.equalsAsciiL( sAccessibleServiceName, + sizeof(sAccessibleServiceName)-1 ); +} + +uno::Sequence< OUString > SAL_CALL SwAccessibleTextFrame::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< OUString > aRet(2); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); + pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); + return aRet; +} + +uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleTextFrame::getImplementationId() + throw(uno::RuntimeException) +{ + SolarMutexGuard aGuard; + static uno::Sequence< sal_Int8 > aId( 16 ); + static sal_Bool bInit = sal_False; + if(!bInit) + { + rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); + bInit = sal_True; + } + return aId; +} + + +// +// XAccessibleRelationSet +// + + +SwFlyFrm* SwAccessibleTextFrame::getFlyFrm() const +{ + SwFlyFrm* pFlyFrm = NULL; + + const SwFrm* pFrm = GetFrm(); + DBG_ASSERT( pFrm != NULL, "frame expected" ); + if( pFrm->IsFlyFrm() ) + { + pFlyFrm = static_cast<SwFlyFrm*>( const_cast<SwFrm*>( pFrm ) ); + } + + return pFlyFrm; +} + +AccessibleRelation SwAccessibleTextFrame::makeRelation( sal_Int16 nType, const SwFlyFrm* pFrm ) +{ + uno::Sequence<uno::Reference<XInterface> > aSequence(1); + aSequence[0] = GetMap()->GetContext( pFrm ); + return AccessibleRelation( nType, aSequence ); +} + + +uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleTextFrame::getAccessibleRelationSet( ) + throw ( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + CHECK_FOR_DEFUNC( XAccessibleContext ); + + // get the frame, and insert prev/next relations into helper + + AccessibleRelationSetHelper* pHelper = new AccessibleRelationSetHelper(); + + SwFlyFrm* pFlyFrm = getFlyFrm(); + DBG_ASSERT( pFlyFrm != NULL, "fly frame expected" ); + + const SwFlyFrm* pPrevFrm = pFlyFrm->GetPrevLink(); + if( pPrevFrm != NULL ) + pHelper->AddRelation( makeRelation( + AccessibleRelationType::CONTENT_FLOWS_FROM, pPrevFrm ) ); + + const SwFlyFrm* pNextFrm = pFlyFrm->GetNextLink(); + if( pNextFrm != NULL ) + pHelper->AddRelation( makeRelation( + AccessibleRelationType::CONTENT_FLOWS_TO, pNextFrm ) ); + + return pHelper; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/acctextframe.hxx b/sw/source/core/access/acctextframe.hxx new file mode 100644 index 000000000000..92c029d69e23 --- /dev/null +++ b/sw/source/core/access/acctextframe.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ACCTEXTFRAME_HXX +#define _ACCTEXTFRAME_HXX +#include "accframebase.hxx" + +class SwFlyFrm; +namespace utl { class AccessibleRelationSetHelper; } +namespace com { namespace star { + namespace accessibility { struct AccessibleRelation; } +} } + +class SwAccessibleTextFrame : public SwAccessibleFrameBase +{ +private: + // #i73249# + ::rtl::OUString msTitle; + ::rtl::OUString msDesc; + // <-- + +protected: + + virtual ~SwAccessibleTextFrame(); + + virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew); + +public: + + SwAccessibleTextFrame( SwAccessibleMap* pInitMap, const SwFlyFrm* pFlyFrm ); + + //===== XAccessibleContext ============================================== + + // #i73249# - Return the object's current name. + virtual ::rtl::OUString SAL_CALL + getAccessibleName (void) + throw (::com::sun::star::uno::RuntimeException); + // <-- + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + getAccessibleDescription (void) + throw (com::sun::star::uno::RuntimeException); + + //===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException); + + /** Return whether the specified service is supported by this class. + */ + virtual sal_Bool SAL_CALL + supportsService (const ::rtl::OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException); + + /** Returns a list of all supported services. In this case that is just + the AccessibleContext service. + */ + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL + getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException); + + //====== XTypeProvider ==================================================== + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) throw(::com::sun::star::uno::RuntimeException); + + + //===== XAccessibleContext::getAccessibleRelationSet ==================== + + // text frame may have accessible relations to their + // predocesor/successor frames + +private: + // helper methods for getAccessibleRelationSet: + SwFlyFrm* getFlyFrm() const; + + com::sun::star::accessibility::AccessibleRelation makeRelation( + sal_Int16 nType, const SwFlyFrm* pFrm ); + +public: + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleRelationSet> SAL_CALL + getAccessibleRelationSet (void) + throw (::com::sun::star::uno::RuntimeException); +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/parachangetrackinginfo.cxx b/sw/source/core/access/parachangetrackinginfo.cxx new file mode 100644 index 000000000000..c98510bd4b74 --- /dev/null +++ b/sw/source/core/access/parachangetrackinginfo.cxx @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sw.hxx" + +#include <parachangetrackinginfo.hxx> + +#include <wrong.hxx> +#include <com/sun/star/text/TextMarkupType.hpp> + +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <docary.hxx> +#include <redline.hxx> + +namespace css = com::sun::star; + +namespace { + void initChangeTrackTextMarkupLists( const SwTxtFrm& rTxtFrm, + SwWrongList*& opChangeTrackInsertionTextMarkupList, + SwWrongList*& opChangeTrackDeletionTextMarkupList, + SwWrongList*& opChangeTrackFormatChangeTextMarkupList ) + { + opChangeTrackInsertionTextMarkupList = new SwWrongList( WRONGLIST_CHANGETRACKING ); + opChangeTrackDeletionTextMarkupList = new SwWrongList( WRONGLIST_CHANGETRACKING ); + opChangeTrackFormatChangeTextMarkupList = new SwWrongList( WRONGLIST_CHANGETRACKING ); + + if ( !rTxtFrm.GetTxtNode() ) + { + OSL_FAIL( "<initChangeTrackTextMarkupLists(..) - missing <SwTxtNode> instance!" ); + return; + } + const SwTxtNode& rTxtNode( *(rTxtFrm.GetTxtNode()) ); + + const IDocumentRedlineAccess* pIDocChangeTrack( rTxtNode.getIDocumentRedlineAccess() ); + if ( !pIDocChangeTrack ) + { + OSL_FAIL( "<initChangeTrackTextMarkupLists(..) - missing <IDocumentRedlineAccess> instance!" ); + return; + } + + if ( !IDocumentRedlineAccess::IsShowChanges( pIDocChangeTrack->GetRedlineMode() ) || + pIDocChangeTrack->GetRedlineTbl().Count() == 0 ) + { + // nothing to do --> empty change track text markup lists. + return; + } + + const sal_uInt16 nIdxOfFirstRedlineForTxtNode = + pIDocChangeTrack->GetRedlinePos( rTxtNode, USHRT_MAX ); + if ( nIdxOfFirstRedlineForTxtNode == USHRT_MAX ) + { + // nothing to do --> empty change track text markup lists. + return; + } + + const xub_StrLen nTxtFrmTextStartPos = rTxtFrm.IsFollow() + ? rTxtFrm.GetOfst() + : 0; + const xub_StrLen nTxtFrmTextEndPos = rTxtFrm.HasFollow() + ? rTxtFrm.GetFollow()->GetOfst() + : rTxtFrm.GetTxt().Len(); + + // iteration over the redlines which overlap with the text node. + const SwRedlineTbl& rRedlineTbl = pIDocChangeTrack->GetRedlineTbl(); + const sal_uInt16 nRedlineCount( rRedlineTbl.Count() ); + for ( sal_uInt16 nActRedline = nIdxOfFirstRedlineForTxtNode; + nActRedline < nRedlineCount; + ++nActRedline) + { + const SwRedline* pActRedline = rRedlineTbl[ nActRedline ]; + if ( pActRedline->Start()->nNode > rTxtNode.GetIndex() ) + { + break; + } + + xub_StrLen nTxtNodeChangeTrackStart( STRING_LEN ); + xub_StrLen nTxtNodeChangeTrackEnd( STRING_LEN ); + pActRedline->CalcStartEnd( rTxtNode.GetIndex(), + nTxtNodeChangeTrackStart, + nTxtNodeChangeTrackEnd ); + if ( nTxtNodeChangeTrackStart > nTxtFrmTextEndPos || + nTxtNodeChangeTrackEnd < nTxtFrmTextStartPos ) + { + // Consider only redlines which overlap with the text frame's text. + continue; + } + + SwWrongList* pMarkupList( 0 ); + switch ( pActRedline->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + { + pMarkupList = opChangeTrackInsertionTextMarkupList; + } + break; + case nsRedlineType_t::REDLINE_DELETE: + { + pMarkupList = opChangeTrackDeletionTextMarkupList; + } + break; + case nsRedlineType_t::REDLINE_FORMAT: + { + pMarkupList = opChangeTrackFormatChangeTextMarkupList; + } + break; + default: + { + // other types are not considered + } + } + if ( pMarkupList ) + { + const xub_StrLen nTxtFrmChangeTrackStart = + nTxtNodeChangeTrackStart <= nTxtFrmTextStartPos + ? nTxtFrmTextStartPos + : nTxtNodeChangeTrackStart; + + const xub_StrLen nTxtFrmChangeTrackEnd = + nTxtNodeChangeTrackEnd >= nTxtFrmTextEndPos + ? nTxtFrmTextEndPos + : nTxtNodeChangeTrackEnd; + + pMarkupList->Insert( rtl::OUString(), 0, + nTxtFrmChangeTrackStart, + nTxtFrmChangeTrackEnd - nTxtFrmChangeTrackStart, + pMarkupList->Count() ); + } + } // eof iteration over the redlines which overlap with the text node + } +} // eof anonymous namespace + +SwParaChangeTrackingInfo::SwParaChangeTrackingInfo( const SwTxtFrm& rTxtFrm ) + : mrTxtFrm( rTxtFrm ) + , mpChangeTrackInsertionTextMarkupList( 0 ) + , mpChangeTrackDeletionTextMarkupList( 0 ) + , mpChangeTrackFormatChangeTextMarkupList( 0 ) +{ +} + + +SwParaChangeTrackingInfo::~SwParaChangeTrackingInfo() +{ + reset(); +} + +void SwParaChangeTrackingInfo::reset() +{ + delete mpChangeTrackInsertionTextMarkupList; + mpChangeTrackInsertionTextMarkupList = 0; + + delete mpChangeTrackDeletionTextMarkupList; + mpChangeTrackDeletionTextMarkupList = 0; + + delete mpChangeTrackFormatChangeTextMarkupList; + mpChangeTrackFormatChangeTextMarkupList = 0; +} + +const SwWrongList* SwParaChangeTrackingInfo::getChangeTrackingTextMarkupList( const sal_Int32 nTextMarkupType ) +{ + SwWrongList* pChangeTrackingTextMarkupList = 0; + + if ( mpChangeTrackInsertionTextMarkupList == 0 ) + { + OSL_ENSURE( mpChangeTrackDeletionTextMarkupList == 0, + "<SwParaChangeTrackingInfo::getChangeTrackingTextMarkupList(..) - <mpChangeTrackDeletionTextMarkupList> expected to be NULL." ); + OSL_ENSURE( mpChangeTrackFormatChangeTextMarkupList == 0, + "<SwParaChangeTrackingInfo::getChangeTrackingTextMarkupList(..) - <mpChangeTrackFormatChangeTextMarkupList> expected to be NULL." ); + initChangeTrackTextMarkupLists( mrTxtFrm, + mpChangeTrackInsertionTextMarkupList, + mpChangeTrackDeletionTextMarkupList, + mpChangeTrackFormatChangeTextMarkupList ); + } + + switch ( nTextMarkupType ) + { + case css::text::TextMarkupType::TRACK_CHANGE_INSERTION: + { + pChangeTrackingTextMarkupList = mpChangeTrackInsertionTextMarkupList; + } + break; + case css::text::TextMarkupType::TRACK_CHANGE_DELETION: + { + pChangeTrackingTextMarkupList = mpChangeTrackDeletionTextMarkupList; + } + break; + case css::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: + { + pChangeTrackingTextMarkupList = mpChangeTrackFormatChangeTextMarkupList; + } + break; + default: + { + OSL_FAIL( "<SwParaChangeTrackingInfo::getChangeTrackingTextMarkupList(..)> - misusage - unexpected text markup type for change tracking." ); + } + } + + return pChangeTrackingTextMarkupList; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/parachangetrackinginfo.hxx b/sw/source/core/access/parachangetrackinginfo.hxx new file mode 100644 index 000000000000..fea7d2fb5f14 --- /dev/null +++ b/sw/source/core/access/parachangetrackinginfo.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _PARACHANGETRACKINGINFO_HXX_ +#define _PARACHANGETRACKINGINFO_HXX_ + +#include <sal/types.h> + +class SwTxtFrm; +class SwWrongList; + +class SwParaChangeTrackingInfo +{ + public: + explicit SwParaChangeTrackingInfo( const SwTxtFrm& rTxtFrm ); + ~SwParaChangeTrackingInfo(); + + void reset(); + + const SwWrongList* getChangeTrackingTextMarkupList( const sal_Int32 nTextMarkupType ); + + private: + SwParaChangeTrackingInfo( const SwParaChangeTrackingInfo& ); + SwParaChangeTrackingInfo& operator=( const SwParaChangeTrackingInfo& ); + + const SwTxtFrm& mrTxtFrm; + + SwWrongList* mpChangeTrackInsertionTextMarkupList; + SwWrongList* mpChangeTrackDeletionTextMarkupList; + SwWrongList* mpChangeTrackFormatChangeTextMarkupList; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/textmarkuphelper.cxx b/sw/source/core/access/textmarkuphelper.cxx new file mode 100644 index 000000000000..c3dd4d7d6bab --- /dev/null +++ b/sw/source/core/access/textmarkuphelper.cxx @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sw.hxx" + +#include <textmarkuphelper.hxx> +#include <accportions.hxx> + +#include <vector> +#include <algorithm> +#include <comphelper/stlunosequence.hxx> + + +#include <com/sun/star/text/TextMarkupType.hpp> +#include <com/sun/star/accessibility/TextSegment.hpp> + +#include <ndtxt.hxx> +#include <wrong.hxx> + +using namespace com::sun::star; + +// helper functions +namespace { + const SwWrongList* getTextMarkupList( const SwTxtNode& rTxtNode, + const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException) + { + const SwWrongList* pTextMarkupList( 0 ); + switch ( nTextMarkupType ) + { + case text::TextMarkupType::SPELLCHECK: + { + pTextMarkupList = rTxtNode.GetWrong(); + } + break; + case text::TextMarkupType::PROOFREADING: + { + // support not implemented yet + pTextMarkupList = 0; + } + break; + case text::TextMarkupType::SMARTTAG: + { + // support not implemented yet + pTextMarkupList = 0; + } + break; + default: + { + throw lang::IllegalArgumentException(); + } + } + + return pTextMarkupList; + } +} + +// implementation of class <SwTextMarkupoHelper> +SwTextMarkupHelper::SwTextMarkupHelper( const SwAccessiblePortionData& rPortionData, + const SwTxtNode& rTxtNode ) + : mrPortionData( rPortionData ) + // #i108125# + , mpTxtNode( &rTxtNode ) + , mpTextMarkupList( 0 ) + // <-- +{ +} + +// #i108125# +SwTextMarkupHelper::SwTextMarkupHelper( const SwAccessiblePortionData& rPortionData, + const SwWrongList& rTextMarkupList ) + : mrPortionData( rPortionData ) + , mpTxtNode( 0 ) + , mpTextMarkupList( &rTextMarkupList ) +{ +} +// <-- + +sal_Int32 SwTextMarkupHelper::getTextMarkupCount( const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException) +{ + sal_Int32 nTextMarkupCount( 0 ); + + // #i108125# + const SwWrongList* pTextMarkupList = + mpTextMarkupList + ? mpTextMarkupList + : getTextMarkupList( *mpTxtNode, nTextMarkupType ); + // <-- + if ( pTextMarkupList ) + { + nTextMarkupCount = pTextMarkupList->Count(); + } + + return nTextMarkupCount; +} +::com::sun::star::accessibility::TextSegment + SwTextMarkupHelper::getTextMarkup( const sal_Int32 nTextMarkupIndex, + const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException) +{ + if ( nTextMarkupIndex >= getTextMarkupCount( nTextMarkupType ) || + nTextMarkupIndex < 0 ) + { + throw lang::IndexOutOfBoundsException(); + } + + ::com::sun::star::accessibility::TextSegment aTextMarkupSegment; + aTextMarkupSegment.SegmentStart = -1; + aTextMarkupSegment.SegmentEnd = -1; + + // #i108125# + const SwWrongList* pTextMarkupList = + mpTextMarkupList + ? mpTextMarkupList + : getTextMarkupList( *mpTxtNode, nTextMarkupType ); + // <-- + if ( pTextMarkupList ) + { + const SwWrongArea* pTextMarkup = + pTextMarkupList->GetElement( static_cast<sal_uInt16>(nTextMarkupIndex) ); + if ( pTextMarkup ) + { + const ::rtl::OUString rText = mrPortionData.GetAccessibleString(); + const sal_Int32 nStartPos = + mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos ); + const sal_Int32 nEndPos = + mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos + pTextMarkup->mnLen ); + aTextMarkupSegment.SegmentText = rText.copy( nStartPos, nEndPos - nStartPos ); + aTextMarkupSegment.SegmentStart = nStartPos; + aTextMarkupSegment.SegmentEnd = nEndPos; + } + else + { + OSL_FAIL( "<SwTextMarkupHelper::getTextMarkup(..)> - missing <SwWrongArea> instance" ); + } + } + + return aTextMarkupSegment; +} + +::com::sun::star::uno::Sequence< ::com::sun::star::accessibility::TextSegment > + SwTextMarkupHelper::getTextMarkupAtIndex( const sal_Int32 nCharIndex, + const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException) +{ + // assumption: + // value of <nCharIndex> is in range [0..length of accessible text) + + const sal_uInt16 nCoreCharIndex = mrPortionData.GetModelPosition( nCharIndex ); + // Handling of portions with core length == 0 at the beginning of the + // paragraph - e.g. numbering portion. + if ( mrPortionData.GetAccessiblePosition( nCoreCharIndex ) > nCharIndex ) + { + return uno::Sequence< ::com::sun::star::accessibility::TextSegment >(); + } + + // #i108125# + const SwWrongList* pTextMarkupList = + mpTextMarkupList + ? mpTextMarkupList + : getTextMarkupList( *mpTxtNode, nTextMarkupType ); + // <-- + ::std::vector< ::com::sun::star::accessibility::TextSegment > aTmpTextMarkups; + if ( pTextMarkupList ) + { + const ::rtl::OUString rText = mrPortionData.GetAccessibleString(); + + const sal_uInt16 nTextMarkupCount = pTextMarkupList->Count(); + for ( sal_uInt16 nTextMarkupIdx = 0; nTextMarkupIdx < nTextMarkupCount; ++nTextMarkupIdx ) + { + const SwWrongArea* pTextMarkup = + pTextMarkupList->GetElement( static_cast<sal_uInt16>(nTextMarkupIdx) ); + OSL_ENSURE( pTextMarkup, + "<SwTextMarkupHelper::getTextMarkup(..)> - missing <SwWrongArea> instance" ); + if ( pTextMarkup && + pTextMarkup->mnPos <= nCoreCharIndex && + nCoreCharIndex < ( pTextMarkup->mnPos + pTextMarkup->mnLen ) ) + { + const sal_Int32 nStartPos = + mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos ); + const sal_Int32 nEndPos = + mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos + pTextMarkup->mnLen ); + ::com::sun::star::accessibility::TextSegment aTextMarkupSegment; + aTextMarkupSegment.SegmentText = rText.copy( nStartPos, nEndPos - nStartPos ); + aTextMarkupSegment.SegmentStart = nStartPos; + aTextMarkupSegment.SegmentEnd = nEndPos; + aTmpTextMarkups.push_back( aTextMarkupSegment ); + } + } + } + + uno::Sequence< ::com::sun::star::accessibility::TextSegment > aTextMarkups( + aTmpTextMarkups.size() ); + ::std::copy( aTmpTextMarkups.begin(), aTmpTextMarkups.end(), + ::comphelper::stl_begin( aTextMarkups ) ); + + return aTextMarkups; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/access/textmarkuphelper.hxx b/sw/source/core/access/textmarkuphelper.hxx new file mode 100644 index 000000000000..57d3152bab2a --- /dev/null +++ b/sw/source/core/access/textmarkuphelper.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _TEXTMARKUPHELPER_HXX_ +#define _TEXTMARKUPHELPER_HXX_ + +#include <sal/types.h> +#include "com/sun/star/lang/IndexOutOfBoundsException.hdl" +#include "com/sun/star/lang/IllegalArgumentException.hdl" +#include "com/sun/star/uno/RuntimeException.hdl" +#include "com/sun/star/uno/Sequence.h" + +namespace com { namespace sun { namespace star { namespace accessibility { +struct TextSegment; +} } } } + +class SwAccessiblePortionData; +class SwTxtNode; +class SwWrongList; // #i108125# +class SwTextMarkupHelper +{ + public: + SwTextMarkupHelper( const SwAccessiblePortionData& rPortionData, + const SwTxtNode& rTxtNode ); + SwTextMarkupHelper( const SwAccessiblePortionData& rPortionData, + const SwWrongList& rTextMarkupList ); // #i108125# + ~SwTextMarkupHelper() {} + + sal_Int32 getTextMarkupCount( const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + ::com::sun::star::accessibility::TextSegment getTextMarkup( + const sal_Int32 nTextMarkupIndex, + const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + ::com::sun::star::uno::Sequence< ::com::sun::star::accessibility::TextSegment > + getTextMarkupAtIndex( const sal_Int32 nCharIndex, + const sal_Int32 nTextMarkupType ) + throw (::com::sun::star::lang::IndexOutOfBoundsException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + private: + SwTextMarkupHelper( const SwTextMarkupHelper& ); + SwTextMarkupHelper& operator=( const SwTextMarkupHelper& ); + + const SwAccessiblePortionData& mrPortionData; + + // #i108125# + const SwTxtNode* mpTxtNode; + const SwWrongList* mpTextMarkupList; + // <-- +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |