summaryrefslogtreecommitdiff
path: root/sw/source/core/access/accpara.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/access/accpara.cxx')
-rw-r--r--sw/source/core/access/accpara.cxx2678
1 files changed, 2678 insertions, 0 deletions
diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx
new file mode 100644
index 000000000000..368e076470ab
--- /dev/null
+++ b/sw/source/core/access/accpara.cxx
@@ -0,0 +1,2678 @@
+ /*************************************************************************
+ *
+ * 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 <vos/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 <unoobj.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>
+// --> OD 2010-02-22 #i10825#
+#include <parachangetrackinginfo.hxx>
+#include <com/sun/star/text/TextMarkupType.hpp>
+// <--
+// --> OD 2010-03-08 #i92233#
+#include <comphelper/stlunosequence.hxx>
+// <--
+
+#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()
+{
+ // --> OD 2004-09-29 #117933# - provide empty description for paragraphs
+ return ::rtl::OUString();
+ // <--
+}
+
+sal_Int32 SwAccessibleParagraph::GetCaretPos()
+{
+ sal_Int32 nRet = -1;
+
+ // get the selection's point, and test whether it's in our node
+ // --> OD 2005-12-20 #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
+ USHORT nIndex = pPoint->nContent.GetIndex();
+ if( GetPortionData().IsValidCorePosition( nIndex ) )
+ {
+ // Yes, it's us!
+ // --> OD 2006-10-19 #70538#
+ // 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
+ // --> OD 2005-12-20 #i27301# - consider adjusted method signature
+ SwPaM* pCrsr = GetCursor( true );
+ // <--
+ if( pCrsr != NULL )
+ {
+ // get SwPosition for my node
+ const SwTxtNode* pNode = GetTxtNode();
+ 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();
+ ULONG nStartIndex = pStart->nNode.GetIndex();
+ SwPosition* pEnd = pCrsr->End();
+ 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
+ USHORT 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
+ USHORT 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;
+}
+
+// --> OD 2005-12-20 #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();
+ // --> OD 2005-12-20 #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( 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)
+ // --> OD 2005-12-20 #i27301# - consider adjusted method signature
+ SwPaM* pCaret = GetCursor( false );
+ // <--
+ 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 );
+ ::vos::ORef < 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;
+ {
+ vos::OGuard aGuard( aMutex );
+ bOldIsHeading = bIsHeading;
+ if( bIsHeading != bNewIsHeading )
+ bIsHeading = bNewIsHeading;
+ }
+
+
+ if( bNewIsHeading != bOldIsHeading || rText != sOldText )
+ {
+ ::rtl::OUString sNewDesc( GetDescription() );
+ ::rtl::OUString sOldDesc;
+ {
+ vos::OGuard 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;
+ {
+ vos::OGuard 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.
+ ::vos::ORef < 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;
+ {
+ vos::OGuard aGuard( aMutex );
+ nPos = nOldCaretPos;
+ }
+ ASSERT( nPos != -1, "focus object should be selected" );
+
+ FireStateChangedEvent( AccessibleStateType::FOCUSED,
+ pWin->HasFocus() && nPos != -1 );
+ }
+}
+
+SwAccessibleParagraph::SwAccessibleParagraph(
+ SwAccessibleMap& rInitMap,
+ const SwTxtFrm& rTxtFrm )
+ // --> OD 2010-02-24 #i108125#
+ : SwClient( const_cast<SwTxtNode*>(rTxtFrm.GetTxtNode()) )
+ // <--
+ , SwAccessibleContext( &rInitMap, AccessibleRole::PARAGRAPH, &rTxtFrm )
+ , sDesc()
+ , pPortionData( NULL )
+ , pHyperTextData( NULL )
+ , nOldCaretPos( -1 )
+ , bIsHeading( sal_False )
+ , aSelectionHelper( *this )
+ // --> OD 2010-02-19 #i108125#
+ , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTxtFrm ) )
+ // <--
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ bIsHeading = IsHeading();
+ // --> OD 2004-09-27 #117970# - set an empty accessibility name for paragraphs
+ SetName( ::rtl::OUString() );
+ // <--
+
+ // If this object has the focus, then it is remembered by the map itself.
+ nOldCaretPos = GetCaretPos();
+}
+
+SwAccessibleParagraph::~SwAccessibleParagraph()
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ delete pPortionData;
+ delete pHyperTextData;
+ // --> OD 2010-02-22 #i108125#
+ delete mpParaChangeTrackInfo;
+ // <--
+}
+
+sal_Bool SwAccessibleParagraph::HasCursor()
+{
+ vos::OGuard 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( 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" );
+
+ USHORT nStart = GetPortionData().GetModelPosition( nStartIndex );
+ USHORT 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
+ USHORT 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 USHORT 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
+ USHORT nModelPos = GetPortionData().GetModelPosition( nPos );
+ lang::Locale aLocale = pBreakIt->GetLocale(
+ GetTxtNode()->GetLang( nModelPos ) );
+
+ // get word boundary, as the Break-Iterator sees fit.
+ const USHORT 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC( XAccessibleContext );
+
+ vos::OGuard aGuard2( aMutex );
+ if( !sDesc.getLength() )
+ sDesc = GetDescription();
+
+ return sDesc;
+}
+
+lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void)
+ throw (IllegalAccessibleComponentStateException, uno::RuntimeException)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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;
+}
+
+/** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
+
+ OD 2005-12-02 #i27138#
+
+ @author OD
+*/
+uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
+ throw ( uno::RuntimeException )
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ CHECK_FOR_DEFUNC( XAccessibleContext );
+
+ utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
+
+ const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm());
+ ASSERT( 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC( XAccessibleContext );
+
+ // get cursor shell
+ SwCrsrShell *pCrsrSh = GetCrsrShell();
+ // --> OD 2005-12-20 #i27301# - consider new method signature
+ SwPaM *pCrsr = GetCursor( false );
+ // <--
+ 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# */
+}
+
+// --> OD 2007-01-17 #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;
+ }
+ // --> OD 2006-07-13 #i63870#
+ // add interface com::sun:star:accessibility::XAccessibleTextAttributes
+ else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) )
+ {
+ uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
+ aRet <<= aAccTextAttr;
+ }
+ // <--
+ // --> OD 2008-06-10 #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();
+ // --> OD 2006-07-13 #i63870#
+ // add type accessibility::XAccessibleTextAttributes
+ // --> OD 2008-06-10 #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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
+
+ sal_Int32 nRet = GetCaretPos();
+ {
+ vos::OGuard aOldCaretPosGuard( aMutex );
+ ASSERT( nRet == nOldCaretPos, "caret pos out of sync" );
+ nOldCaretPos = nRet;
+ }
+ if( -1 != nRet )
+ {
+ ::vos::ORef < SwAccessibleContext > xThis( this );
+ GetMap()->SetCursorContext( xThis );
+ }
+
+ return nRet;
+}
+
+sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
+ throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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();
+}
+
+// --> OD 2006-07-20 #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)
+{
+
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ 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;
+ }
+
+// // create a (dummy) text portion for the sole purpose of calling
+// // getPropertyValues on it
+// Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 );
+
+// // get values
+// Sequence<OUString> aNames = getAttributeNames();
+// sal_Int32 nLength = aNames.getLength();
+// Sequence<Any> aAnys( nLength );
+// aAnys = xPortion->getPropertyValues( aNames );
+
+// // copy names + anys into return sequence
+// Sequence<PropertyValue> aValues( aNames.getLength() );
+// const OUString* pNames = aNames.getConstArray();
+// const Any* pAnys = aAnys.getConstArray();
+// PropertyValue* pValues = aValues.getArray();
+// for( sal_Int32 i = 0; i < nLength; i++ )
+// {
+// PropertyValue& rValue = pValues[i];
+// rValue.Name = pNames[i];
+// rValue.Value = pAnys[i];
+// rValue.Handle = -1; // handle not supported
+// rValue.State = PropertyState_DIRECT_VALUE; // states not supported
+// }
+
+// // adjust background color if we're in a gray portion
+// DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name.
+// equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")),
+// "Please adjust CHAR_BACK_COLOR_POS constant." );
+// if( GetPortionData().IsInGrayPortion( nIndex ) )
+// pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
+
+ return aValues;
+}
+
+// --> OD 2006-07-11 #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 ) );
+ }
+ // --> OD 2007-11-12 #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>
+ ASSERT( 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;
+ }
+
+ // --> OD 2007-01-15 #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;
+ }
+ }
+ // <--
+
+ // --> OD 2007-01-15 #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 )
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
+
+ tAccParaPropValMap aDefAttrSeq;
+ _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
+
+ // --> OD 2010-03-08 #i92233#
+ static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "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;
+ }
+
+ // --> OD 2010-03-08 #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<USHORT>(nIndex) );
+ SwPosition* pEndPos = new SwPosition( *pTxtNode );
+ pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<USHORT>(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 );
+ // --> OD 2007-11-12 #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, TRUE, 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()), 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, TRUE, TRUE);
+ aSet.Put( aCharAttrsAtPaM );
+ }
+ // <--
+
+ // build-up sequence containing the run attributes <rRunAttrSeq>
+ {
+ tAccParaPropValMap aRunAttrSeq;
+ {
+ // --> OD 2007-11-12 #i82637#
+ tAccParaPropValMap aDefAttrSeq;
+ uno::Sequence< ::rtl::OUString > aDummy;
+ _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true );
+ // <--
+
+ 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 );
+ // --> OD 2007-11-12 #i82637#
+ // Found character attributes, whose value equals the value of
+ // the corresponding default character attributes, are excluded.
+ if ( aSet.GetItemState( aPropIt->nWID, 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 )
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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 = TRUE;
+ aMoveState.bRealWidth = TRUE;
+ SwSpecialPos aSpecialPos;
+ SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
+
+ USHORT 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
+
+ return GetString().getLength();
+}
+
+sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
+ throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+
+ 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 = 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
+
+ sal_Int32 nStart, nEnd;
+ GetSelection( nStart, nEnd );
+ return nStart;
+}
+
+sal_Int32 SwAccessibleParagraph::getSelectionEnd()
+ throw (uno::RuntimeException)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
+
+ return GetString();
+}
+
+::rtl::OUString SwAccessibleParagraph::getTextRange(
+ sal_Int32 nStartIndex, sal_Int32 nEndIndex )
+ throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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 );
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ // 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 );
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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 );
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ 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
+ USHORT 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ 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);
+}
+
+// --> OD 2004-11-16 #111714# - 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+
+ CHECK_FOR_DEFUNC( XAccessibleHypertext );
+
+ sal_Int32 nCount = 0;
+ // --> OD 2007-06-27 #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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ CHECK_FOR_DEFUNC( XAccessibleHypertext );
+
+ uno::Reference< XAccessibleHyperlink > xRet;
+
+ // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
+// if( !IsEditableState() )
+ // <--
+ {
+ 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)
+{
+ vos::OGuard aGuard(Application::GetSolarMutex());
+ CHECK_FOR_DEFUNC( XAccessibleHypertext );
+
+ // parameter checking
+ sal_Int32 nLength = GetString().getLength();
+ if ( ! IsValidPosition( nCharIndex, nLength ) )
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+
+ sal_Int32 nRet = -1;
+ // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
+// if( !IsEditableState() )
+ // <--
+ {
+ 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;
+}
+
+// --> OD 2008-05-26 #i71360#
+// --> OD 2010-02-22 #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 );
+}
+// <--
+
+// --> OD 2008-05-29 #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;
+}
+
+// --> OD 2010-02-19 #i108125#
+void SwAccessibleParagraph::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew )
+{
+ mpParaChangeTrackInfo->reset();
+
+ SwClient::Modify( pOld, pNew );
+}
+// <--