xref: /aoo42x/main/sw/source/core/access/accpara.cxx (revision cdf0e10c)
1  /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <txtfrm.hxx>
32 #include <flyfrm.hxx>
33 #include <ndtxt.hxx>
34 #include <pam.hxx>
35 #include <unotextrange.hxx>
36 #include <unocrsrhelper.hxx>
37 #include <crstate.hxx>
38 #include <accmap.hxx>
39 #include <fesh.hxx>
40 #include <viewopt.hxx>
41 #include <vos/mutex.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/window.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <com/sun/star/accessibility/AccessibleRole.hpp>
46 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
47 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
48 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
49 #include <unotools/accessiblestatesethelper.hxx>
50 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
51 #include <com/sun/star/i18n/WordType.hpp>
52 #include <com/sun/star/i18n/XBreakIterator.hpp>
53 #include <com/sun/star/beans/UnknownPropertyException.hpp>
54 #include <breakit.hxx>
55 #include <accpara.hxx>
56 #include <access.hrc>
57 #include <accportions.hxx>
58 #include <sfx2/viewsh.hxx>      // for ExecuteAtViewShell(...)
59 #include <sfx2/viewfrm.hxx>      // for ExecuteAtViewShell(...)
60 #include <sfx2/dispatch.hxx>    // for ExecuteAtViewShell(...)
61 #include <unotools/charclass.hxx>   // for GetWordBoundary
62 // for get/setCharacterAttribute(...)
63 #include <unocrsr.hxx>
64 //#include <unoobj.hxx>
65 #include <unoport.hxx>
66 #include <doc.hxx>
67 #include <crsskip.hxx>
68 #include <txtatr.hxx>
69 #include <acchyperlink.hxx>
70 #include <acchypertextdata.hxx>
71 #include <unotools/accessiblerelationsethelper.hxx>
72 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
73 #include <comphelper/accessibletexthelper.hxx>
74 #include <unomap.hxx>
75 #include <unoprnms.hxx>
76 #include <com/sun/star/text/WritingMode2.hpp>
77 #include <editeng/brshitem.hxx>
78 #include <viewimp.hxx>
79 #include <boost/scoped_ptr.hpp>
80 #include <textmarkuphelper.hxx>
81 // --> OD 2010-02-22 #i10825#
82 #include <parachangetrackinginfo.hxx>
83 #include <com/sun/star/text/TextMarkupType.hpp>
84 // <--
85 // --> OD 2010-03-08 #i92233#
86 #include <comphelper/stlunosequence.hxx>
87 // <--
88 
89 #include <algorithm>
90 
91 using namespace ::com::sun::star;
92 using namespace ::com::sun::star::accessibility;
93 
94 using beans::PropertyValue;
95 using beans::XMultiPropertySet;
96 using beans::UnknownPropertyException;
97 using beans::PropertyState_DIRECT_VALUE;
98 
99 using std::max;
100 using std::min;
101 using std::sort;
102 
103 namespace com { namespace sun { namespace star {
104     namespace text {
105         class XText;
106     }
107 } } }
108 
109 
110 const sal_Char sServiceName[] = "com.sun.star.text.AccessibleParagraphView";
111 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView";
112 const xub_StrLen MAX_DESC_TEXT_LEN = 40;
113 const SwTxtNode* SwAccessibleParagraph::GetTxtNode() const
114 {
115     const SwFrm* pFrm = GetFrm();
116     DBG_ASSERT( pFrm->IsTxtFrm(), "The text frame has mutated!" );
117 
118     const SwTxtNode* pNode = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode();
119     DBG_ASSERT( pNode != NULL, "A text frame without a text node." );
120 
121     return pNode;
122 }
123 
124 ::rtl::OUString SwAccessibleParagraph::GetString()
125 {
126     return GetPortionData().GetAccessibleString();
127 }
128 
129 ::rtl::OUString SwAccessibleParagraph::GetDescription()
130 {
131     // --> OD 2004-09-29 #117933# - provide empty description for paragraphs
132     return ::rtl::OUString();
133     // <--
134 }
135 
136 sal_Int32 SwAccessibleParagraph::GetCaretPos()
137 {
138     sal_Int32 nRet = -1;
139 
140     // get the selection's point, and test whether it's in our node
141     // --> OD 2005-12-20 #i27301# - consider adjusted method signature
142     SwPaM* pCaret = GetCursor( false );  // caret is first PaM in PaM-ring
143     // <--
144     if( pCaret != NULL )
145     {
146         const SwTxtNode* pNode = GetTxtNode();
147 
148         // check whether the point points into 'our' node
149         SwPosition* pPoint = pCaret->GetPoint();
150         if( pNode->GetIndex() == pPoint->nNode.GetIndex() )
151         {
152             // same node? Then check whether it's also within 'our' part
153             // of the paragraph
154             sal_uInt16 nIndex = pPoint->nContent.GetIndex();
155             if( GetPortionData().IsValidCorePosition( nIndex ) )
156             {
157                 // Yes, it's us!
158                 // --> OD 2006-10-19 #70538#
159                 // consider that cursor/caret is in front of the list label
160                 if ( pCaret->IsInFrontOfLabel() )
161                 {
162                     nRet = 0;
163                 }
164                 else
165                 {
166                     nRet = GetPortionData().GetAccessiblePosition( nIndex );
167                 }
168                 // <--
169 
170                 DBG_ASSERT( nRet >= 0, "invalid cursor?" );
171                 DBG_ASSERT( nRet <= GetPortionData().GetAccessibleString().
172                                               getLength(), "invalid cursor?" );
173             }
174             // else: in this paragraph, but in different frame
175         }
176         // else: not in this paragraph
177     }
178     // else: no cursor -> no caret
179 
180     return nRet;
181 }
182 
183 sal_Bool SwAccessibleParagraph::GetSelection(
184     sal_Int32& nStart, sal_Int32& nEnd)
185 {
186     sal_Bool bRet = sal_False;
187     nStart = -1;
188     nEnd = -1;
189 
190     // get the selection, and test whether it affects our text node
191     // --> OD 2005-12-20 #i27301# - consider adjusted method signature
192     SwPaM* pCrsr = GetCursor( true );
193     // <--
194     if( pCrsr != NULL )
195     {
196         // get SwPosition for my node
197         const SwTxtNode* pNode = GetTxtNode();
198         sal_uLong nHere = pNode->GetIndex();
199 
200         // iterate over ring
201         SwPaM* pRingStart = pCrsr;
202         do
203         {
204             // ignore, if no mark
205             if( pCrsr->HasMark() )
206             {
207                 // check whether nHere is 'inside' pCrsr
208                 SwPosition* pStart = pCrsr->Start();
209                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
210                 SwPosition* pEnd = pCrsr->End();
211                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
212                 if( ( nHere >= nStartIndex ) &&
213                     ( nHere <= nEndIndex )      )
214                 {
215                     // translate start and end positions
216 
217                     // start position
218                     sal_Int32 nLocalStart = -1;
219                     if( nHere > nStartIndex )
220                     {
221                         // selection starts in previous node:
222                         // then our local selection starts with the paragraph
223                         nLocalStart = 0;
224                     }
225                     else
226                     {
227                         DBG_ASSERT( nHere == nStartIndex,
228                                     "miscalculated index" );
229 
230                         // selection starts in this node:
231                         // then check whether it's before or inside our part of
232                         // the paragraph, and if so, get the proper position
233                         sal_uInt16 nCoreStart = pStart->nContent.GetIndex();
234                         if( nCoreStart <
235                             GetPortionData().GetFirstValidCorePosition() )
236                         {
237                             nLocalStart = 0;
238                         }
239                         else if( nCoreStart <=
240                                  GetPortionData().GetLastValidCorePosition() )
241                         {
242                             DBG_ASSERT(
243                                 GetPortionData().IsValidCorePosition(
244                                                                   nCoreStart ),
245                                  "problem determining valid core position" );
246 
247                             nLocalStart =
248                                 GetPortionData().GetAccessiblePosition(
249                                                                   nCoreStart );
250                         }
251                     }
252 
253                     // end position
254                     sal_Int32 nLocalEnd = -1;
255                     if( nHere < nEndIndex )
256                     {
257                         // selection ends in following node:
258                         // then our local selection extends to the end
259                         nLocalEnd = GetPortionData().GetAccessibleString().
260                                                                    getLength();
261                     }
262                     else
263                     {
264                         DBG_ASSERT( nHere == nEndIndex,
265                                     "miscalculated index" );
266 
267                         // selection ends in this node: then select everything
268                         // before our part of the node
269                         sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex();
270                         if( nCoreEnd >
271                                 GetPortionData().GetLastValidCorePosition() )
272                         {
273                             // selection extends beyond out part of this para
274                             nLocalEnd = GetPortionData().GetAccessibleString().
275                                                                    getLength();
276                         }
277                         else if( nCoreEnd >=
278                                  GetPortionData().GetFirstValidCorePosition() )
279                         {
280                             // selection is inside our part of this para
281                             DBG_ASSERT(
282                                 GetPortionData().IsValidCorePosition(
283                                                                   nCoreEnd ),
284                                  "problem determining valid core position" );
285 
286                             nLocalEnd = GetPortionData().GetAccessiblePosition(
287                                                                    nCoreEnd );
288                         }
289                     }
290 
291                     if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
292                     {
293                         nStart = nLocalStart;
294                         nEnd = nLocalEnd;
295                         bRet = sal_True;
296                     }
297                 }
298                 // else: this PaM doesn't point to this paragraph
299             }
300             // else: this PaM is collapsed and doesn't select anything
301 
302             // next PaM in ring
303             pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
304         }
305         while( !bRet && (pCrsr != pRingStart) );
306     }
307     // else: nocursor -> no selection
308 
309     return bRet;
310 }
311 
312 // --> OD 2005-12-20 #i27301# - new parameter <_bForSelection>
313 SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection )
314 {
315     // get the cursor shell; if we don't have any, we don't have a
316     // cursor/selection either
317     SwPaM* pCrsr = NULL;
318     SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
319     // --> OD 2005-12-20 #i27301#
320     // - if cursor is retrieved for selection, the cursors for a table selection
321     //   has to be returned.
322     if ( pCrsrShell != NULL &&
323          ( _bForSelection || !pCrsrShell->IsTableMode() ) )
324     // <--
325     {
326 		SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell )
327 							? static_cast< SwFEShell * >( pCrsrShell ) : 0;
328 		if( !pFESh ||
329 			!(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) )
330 		{
331 			// get the selection, and test whether it affects our text node
332 			pCrsr = pCrsrShell->GetCrsr( sal_False /* ??? */ );
333 		}
334     }
335 
336     return pCrsr;
337 }
338 
339 sal_Bool SwAccessibleParagraph::IsHeading() const
340 {
341 	const SwTxtNode *pTxtNd = GetTxtNode();
342 	return pTxtNd->IsOutline();
343 }
344 
345 void SwAccessibleParagraph::GetStates(
346 		::utl::AccessibleStateSetHelper& rStateSet )
347 {
348 	SwAccessibleContext::GetStates( rStateSet );
349 
350 	// MULTILINE
351 	rStateSet.AddState( AccessibleStateType::MULTI_LINE );
352 
353 	// MULTISELECTABLE
354 	SwCrsrShell *pCrsrSh = GetCrsrShell();
355 	if( pCrsrSh )
356 		rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
357 
358 	// FOCUSABLE
359 	if( pCrsrSh )
360 		rStateSet.AddState( AccessibleStateType::FOCUSABLE );
361 
362 	// FOCUSED (simulates node index of cursor)
363     // --> OD 2005-12-20 #i27301# - consider adjusted method signature
364     SwPaM* pCaret = GetCursor( false );
365     // <--
366 	const SwTxtNode* pTxtNd = GetTxtNode();
367 	if( pCaret != 0 && pTxtNd != 0 &&
368 		pTxtNd->GetIndex() == pCaret->GetPoint()->nNode.GetIndex() &&
369 		nOldCaretPos != -1)
370 	{
371 		Window *pWin = GetWindow();
372 		if( pWin && pWin->HasFocus() )
373 			rStateSet.AddState( AccessibleStateType::FOCUSED );
374 		::vos::ORef < SwAccessibleContext > xThis( this );
375 		GetMap()->SetCursorContext( xThis );
376 	}
377 }
378 
379 void SwAccessibleParagraph::_InvalidateContent( sal_Bool bVisibleDataFired )
380 {
381     ::rtl::OUString sOldText( GetString() );
382 
383 	ClearPortionData();
384 
385     const ::rtl::OUString& rText = GetString();
386 
387 	if( rText != sOldText )
388 	{
389 		// The text is changed
390 		AccessibleEventObject aEvent;
391 		aEvent.EventId = AccessibleEventId::TEXT_CHANGED;
392 
393         // determine exact changes between sOldText and rText
394         comphelper::OCommonAccessibleText::implInitTextChangedEvent(
395             sOldText, rText,
396             aEvent.OldValue, aEvent.NewValue );
397 
398 		FireAccessibleEvent( aEvent );
399 	}
400 	else if( !bVisibleDataFired )
401 	{
402 		FireVisibleDataEvent();
403 	}
404 
405 	sal_Bool bNewIsHeading = IsHeading();
406 	sal_Bool bOldIsHeading;
407 	{
408 		vos::OGuard aGuard( aMutex );
409 		bOldIsHeading = bIsHeading;
410 		if( bIsHeading != bNewIsHeading )
411 			bIsHeading = bNewIsHeading;
412 	}
413 
414 
415 	if( bNewIsHeading != bOldIsHeading || rText != sOldText )
416 	{
417         ::rtl::OUString sNewDesc( GetDescription() );
418         ::rtl::OUString sOldDesc;
419 		{
420 			vos::OGuard aGuard( aMutex );
421 			sOldDesc = sDesc;
422 			if( sDesc != sNewDesc )
423 				sDesc = sNewDesc;
424 		}
425 
426 		if( sNewDesc != sOldDesc )
427 		{
428 			// The text is changed
429 			AccessibleEventObject aEvent;
430 			aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
431 			aEvent.OldValue <<= sOldDesc;
432 			aEvent.NewValue <<= sNewDesc;
433 
434 			FireAccessibleEvent( aEvent );
435 		}
436 	}
437 }
438 
439 void SwAccessibleParagraph::_InvalidateCursorPos()
440 {
441 	// The text is changed
442 	sal_Int32 nNew = GetCaretPos();
443 	sal_Int32 nOld;
444 	{
445 		vos::OGuard aGuard( aMutex );
446 		nOld = nOldCaretPos;
447 		nOldCaretPos = nNew;
448 	}
449 	if( -1 != nNew )
450 	{
451 		// remember that object as the one that has the caret. This is
452 		// neccessary to notify that object if the cursor leaves it.
453 		::vos::ORef < SwAccessibleContext > xThis( this );
454 		GetMap()->SetCursorContext( xThis );
455 	}
456 
457 	Window *pWin = GetWindow();
458 	if( nOld != nNew )
459 	{
460 		// The cursor's node position is sumilated by the focus!
461 		if( pWin && pWin->HasFocus() && -1 == nOld )
462 			FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True );
463 
464 
465 		AccessibleEventObject aEvent;
466 		aEvent.EventId = AccessibleEventId::CARET_CHANGED;
467 		aEvent.OldValue <<= nOld;
468 		aEvent.NewValue <<= nNew;
469 
470 		FireAccessibleEvent( aEvent );
471 
472 		if( pWin && pWin->HasFocus() && -1 == nNew )
473 			FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_False );
474 	}
475 }
476 
477 void SwAccessibleParagraph::_InvalidateFocus()
478 {
479 	Window *pWin = GetWindow();
480 	if( pWin )
481 	{
482 		sal_Int32 nPos;
483 		{
484 			vos::OGuard aGuard( aMutex );
485 			nPos = nOldCaretPos;
486 		}
487 		ASSERT( nPos != -1, "focus object should be selected" );
488 
489 		FireStateChangedEvent( AccessibleStateType::FOCUSED,
490 							   pWin->HasFocus() && nPos != -1 );
491 	}
492 }
493 
494 SwAccessibleParagraph::SwAccessibleParagraph(
495         SwAccessibleMap& rInitMap,
496         const SwTxtFrm& rTxtFrm )
497     // --> OD 2010-02-24 #i108125#
498     : SwClient( const_cast<SwTxtNode*>(rTxtFrm.GetTxtNode()) )
499     // <--
500     , SwAccessibleContext( &rInitMap, AccessibleRole::PARAGRAPH, &rTxtFrm )
501     , sDesc()
502     , pPortionData( NULL )
503     , pHyperTextData( NULL )
504     , nOldCaretPos( -1 )
505     , bIsHeading( sal_False )
506     , aSelectionHelper( *this )
507     // --> OD 2010-02-19 #i108125#
508     , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTxtFrm ) )
509     // <--
510 {
511 	vos::OGuard aGuard(Application::GetSolarMutex());
512 
513 	bIsHeading = IsHeading();
514     // --> OD 2004-09-27 #117970# - set an empty accessibility name for paragraphs
515     SetName( ::rtl::OUString() );
516     // <--
517 
518 	// If this object has the focus, then it is remembered by the map itself.
519 	nOldCaretPos = GetCaretPos();
520 }
521 
522 SwAccessibleParagraph::~SwAccessibleParagraph()
523 {
524 	vos::OGuard aGuard(Application::GetSolarMutex());
525 
526     delete pPortionData;
527     delete pHyperTextData;
528     // --> OD 2010-02-22 #i108125#
529     delete mpParaChangeTrackInfo;
530     // <--
531 }
532 
533 sal_Bool SwAccessibleParagraph::HasCursor()
534 {
535 	vos::OGuard aGuard( aMutex );
536 	return nOldCaretPos != -1;
537 }
538 
539 void SwAccessibleParagraph::UpdatePortionData()
540     throw( uno::RuntimeException )
541 {
542     // obtain the text frame
543     DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
544     DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
545     const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
546 
547     // build new portion data
548     delete pPortionData;
549     pPortionData = new SwAccessiblePortionData(
550         pFrm->GetTxtNode(), GetMap()->GetShell()->GetViewOptions() );
551     pFrm->VisitPortions( *pPortionData );
552 
553     DBG_ASSERT( pPortionData != NULL, "UpdatePortionData() failed" );
554 }
555 
556 void SwAccessibleParagraph::ClearPortionData()
557 {
558     delete pPortionData;
559     pPortionData = NULL;
560 
561 	delete pHyperTextData;
562 	pHyperTextData = 0;
563 }
564 
565 
566 void SwAccessibleParagraph::ExecuteAtViewShell( sal_uInt16 nSlot )
567 {
568     DBG_ASSERT( GetMap() != NULL, "no map?" );
569     ViewShell* pViewShell = GetMap()->GetShell();
570 
571     DBG_ASSERT( pViewShell != NULL, "View shell exptected!" );
572     SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell();
573 
574     DBG_ASSERT( pSfxShell != NULL, "SfxViewShell shell exptected!" );
575     if( !pSfxShell )
576 		return;
577 
578 	SfxViewFrame *pFrame = pSfxShell->GetViewFrame();
579     DBG_ASSERT( pFrame != NULL, "View frame exptected!" );
580 	if( !pFrame )
581 		return;
582 
583 	SfxDispatcher *pDispatcher = pFrame->GetDispatcher();
584     DBG_ASSERT( pDispatcher != NULL, "Dispatcher exptected!" );
585 	if( !pDispatcher )
586 		return;
587 
588 	pDispatcher->Execute( nSlot );
589 }
590 
591 SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion(
592     sal_Int32 nStartIndex,
593     sal_Int32 nEndIndex )
594 {
595     DBG_ASSERT( (IsValidChar(nStartIndex, GetString().getLength()) &&
596                  (nEndIndex == -1)) ||
597                 IsValidRange(nStartIndex, nEndIndex, GetString().getLength()),
598                 "please check parameters before calling this method" );
599 
600     sal_uInt16 nStart = GetPortionData().GetModelPosition( nStartIndex );
601     sal_uInt16 nEnd = (nEndIndex == -1) ? (nStart + 1) :
602                         GetPortionData().GetModelPosition( nEndIndex );
603 
604     // create UNO cursor
605     SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() );
606     SwIndex aIndex( pTxtNode, nStart );
607     SwPosition aStartPos( *pTxtNode, aIndex );
608     SwUnoCrsr* pUnoCursor = pTxtNode->GetDoc()->CreateUnoCrsr( aStartPos );
609     pUnoCursor->SetMark();
610     pUnoCursor->GetMark()->nContent = nEnd;
611 
612     // create a (dummy) text portion to be returned
613     uno::Reference<text::XText> aEmpty;
614     SwXTextPortion* pPortion =
615         new SwXTextPortion ( pUnoCursor, aEmpty, PORTION_TEXT);
616     delete pUnoCursor;
617 
618     return pPortion;
619 }
620 
621 
622 //
623 // range checking for parameter
624 //
625 
626 sal_Bool SwAccessibleParagraph::IsValidChar(
627     sal_Int32 nPos, sal_Int32 nLength)
628 {
629     return (nPos >= 0) && (nPos < nLength);
630 }
631 
632 sal_Bool SwAccessibleParagraph::IsValidPosition(
633     sal_Int32 nPos, sal_Int32 nLength)
634 {
635     return (nPos >= 0) && (nPos <= nLength);
636 }
637 
638 sal_Bool SwAccessibleParagraph::IsValidRange(
639     sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength)
640 {
641     return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength);
642 }
643 
644 
645 //
646 // text boundaries
647 //
648 
649 
650 sal_Bool SwAccessibleParagraph::GetCharBoundary(
651     i18n::Boundary& rBound,
652     const ::rtl::OUString&,
653     sal_Int32 nPos )
654 {
655     rBound.startPos = nPos;
656     rBound.endPos = nPos+1;
657     return sal_True;
658 }
659 
660 sal_Bool SwAccessibleParagraph::GetWordBoundary(
661     i18n::Boundary& rBound,
662     const ::rtl::OUString& rText,
663     sal_Int32 nPos )
664 {
665     sal_Bool bRet = sal_False;
666 
667     // now ask the Break-Iterator for the word
668     DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
669     DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
670     if( pBreakIt->GetBreakIter().is() )
671     {
672         // get locale for this position
673         sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos );
674         lang::Locale aLocale = pBreakIt->GetLocale(
675                               GetTxtNode()->GetLang( nModelPos ) );
676 
677         // which type of word are we interested in?
678         // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.)
679         const sal_uInt16 nWordType = i18n::WordType::ANY_WORD;
680 
681         // get word boundary, as the Break-Iterator sees fit.
682         rBound = pBreakIt->GetBreakIter()->getWordBoundary(
683             rText, nPos, aLocale, nWordType, sal_True );
684 
685         // It's a word if the first character is an alpha-numeric character.
686         bRet = GetAppCharClass().isLetterNumeric(
687             rText.getStr()[ rBound.startPos ] );
688     }
689     else
690     {
691         // no break Iterator -> no word
692         rBound.startPos = nPos;
693         rBound.endPos = nPos;
694     }
695 
696     return bRet;
697 }
698 
699 sal_Bool SwAccessibleParagraph::GetSentenceBoundary(
700     i18n::Boundary& rBound,
701     const ::rtl::OUString&,
702     sal_Int32 nPos )
703 {
704     GetPortionData().GetSentenceBoundary( rBound, nPos );
705     return sal_True;
706 }
707 
708 sal_Bool SwAccessibleParagraph::GetLineBoundary(
709     i18n::Boundary& rBound,
710     const ::rtl::OUString& rText,
711     sal_Int32 nPos )
712 {
713 	if( rText.getLength() == nPos )
714 		GetPortionData().GetLastLineBoundary( rBound );
715 	else
716 		GetPortionData().GetLineBoundary( rBound, nPos );
717     return sal_True;
718 }
719 
720 sal_Bool SwAccessibleParagraph::GetParagraphBoundary(
721     i18n::Boundary& rBound,
722     const ::rtl::OUString& rText,
723     sal_Int32 )
724 {
725     rBound.startPos = 0;
726     rBound.endPos = rText.getLength();
727     return sal_True;
728 }
729 
730 sal_Bool SwAccessibleParagraph::GetAttributeBoundary(
731     i18n::Boundary& rBound,
732     const ::rtl::OUString&,
733     sal_Int32 nPos )
734 {
735     GetPortionData().GetAttributeBoundary( rBound, nPos );
736     return sal_True;
737 }
738 
739 sal_Bool SwAccessibleParagraph::GetGlyphBoundary(
740     i18n::Boundary& rBound,
741     const ::rtl::OUString& rText,
742     sal_Int32 nPos )
743 {
744     sal_Bool bRet = sal_False;
745 
746     // ask the Break-Iterator for the glyph by moving one cell
747     // forward, and then one cell back
748     DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
749     DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
750     if( pBreakIt->GetBreakIter().is() )
751     {
752         // get locale for this position
753         sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos );
754         lang::Locale aLocale = pBreakIt->GetLocale(
755                               GetTxtNode()->GetLang( nModelPos ) );
756 
757         // get word boundary, as the Break-Iterator sees fit.
758         const sal_uInt16 nIterMode = i18n::CharacterIteratorMode::SKIPCELL;
759         sal_Int32 nDone = 0;
760         rBound.endPos = pBreakIt->GetBreakIter()->nextCharacters(
761              rText, nPos, aLocale, nIterMode, 1, nDone );
762         rBound.startPos = pBreakIt->GetBreakIter()->previousCharacters(
763              rText, rBound.endPos, aLocale, nIterMode, 1, nDone );
764 
765         DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" );
766         DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" );
767     }
768     else
769     {
770         // no break Iterator -> no glyph
771         rBound.startPos = nPos;
772         rBound.endPos = nPos;
773     }
774 
775     return bRet;
776 }
777 
778 
779 sal_Bool SwAccessibleParagraph::GetTextBoundary(
780     i18n::Boundary& rBound,
781     const ::rtl::OUString& rText,
782     sal_Int32 nPos,
783     sal_Int16 nTextType )
784     throw (
785         lang::IndexOutOfBoundsException,
786         lang::IllegalArgumentException,
787         uno::RuntimeException)
788 {
789     // error checking
790     if( !( AccessibleTextType::LINE == nTextType
791 				? IsValidPosition( nPos, rText.getLength() )
792 				: IsValidChar( nPos, rText.getLength() ) ) )
793         throw lang::IndexOutOfBoundsException();
794 
795     sal_Bool bRet;
796 
797     switch( nTextType )
798     {
799         case AccessibleTextType::WORD:
800             bRet = GetWordBoundary( rBound, rText, nPos );
801             break;
802 
803         case AccessibleTextType::SENTENCE:
804             bRet = GetSentenceBoundary( rBound, rText, nPos );
805             break;
806 
807         case AccessibleTextType::PARAGRAPH:
808             bRet = GetParagraphBoundary( rBound, rText, nPos );
809             break;
810 
811         case AccessibleTextType::CHARACTER:
812             bRet = GetCharBoundary( rBound, rText, nPos );
813             break;
814 
815         case AccessibleTextType::LINE:
816             bRet = GetLineBoundary( rBound, rText, nPos );
817             break;
818 
819         case AccessibleTextType::ATTRIBUTE_RUN:
820             bRet = GetAttributeBoundary( rBound, rText, nPos );
821             break;
822 
823         case AccessibleTextType::GLYPH:
824             bRet = GetGlyphBoundary( rBound, rText, nPos );
825             break;
826 
827         default:
828             throw lang::IllegalArgumentException( );
829     }
830 
831     return bRet;
832 }
833 
834 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void)
835         throw (uno::RuntimeException)
836 {
837 	vos::OGuard aGuard(Application::GetSolarMutex());
838 
839 	CHECK_FOR_DEFUNC( XAccessibleContext );
840 
841 	vos::OGuard aGuard2( aMutex );
842 	if( !sDesc.getLength() )
843 		sDesc = GetDescription();
844 
845     return sDesc;
846 }
847 
848 lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void)
849         throw (IllegalAccessibleComponentStateException, uno::RuntimeException)
850 {
851 	vos::OGuard aGuard(Application::GetSolarMutex());
852 
853 	SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() );
854 	if( !pTxtFrm )
855 	{
856 		THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" );
857 	}
858 
859 	const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode();
860     lang::Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) );
861 
862 	return aLoc;
863 }
864 
865 /** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
866 
867     OD 2005-12-02 #i27138#
868 
869     @author OD
870 */
871 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
872     throw ( uno::RuntimeException )
873 {
874     vos::OGuard aGuard(Application::GetSolarMutex());
875     CHECK_FOR_DEFUNC( XAccessibleContext );
876 
877     utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
878 
879     const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm());
880     ASSERT( pTxtFrm,
881             "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame");
882     if ( pTxtFrm )
883     {
884         const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) );
885         if ( pPrevCntFrm )
886         {
887             uno::Sequence< uno::Reference<XInterface> > aSequence(1);
888             aSequence[0] = GetMap()->GetContext( pPrevCntFrm );
889             AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
890                                         aSequence );
891             pHelper->AddRelation( aAccRel );
892         }
893 
894         const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) );
895         if ( pNextCntFrm )
896         {
897             uno::Sequence< uno::Reference<XInterface> > aSequence(1);
898             aSequence[0] = GetMap()->GetContext( pNextCntFrm );
899             AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
900                                         aSequence );
901             pHelper->AddRelation( aAccRel );
902         }
903     }
904 
905     return pHelper;
906 }
907 
908 void SAL_CALL SwAccessibleParagraph::grabFocus()
909         throw (uno::RuntimeException)
910 {
911 	vos::OGuard aGuard(Application::GetSolarMutex());
912 
913 	CHECK_FOR_DEFUNC( XAccessibleContext );
914 
915     // get cursor shell
916 	SwCrsrShell *pCrsrSh = GetCrsrShell();
917     // --> OD 2005-12-20 #i27301# - consider new method signature
918     SwPaM *pCrsr = GetCursor( false );
919     // <--
920 	const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
921 	const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode();
922 
923     if( pCrsrSh != 0 && pTxtNd != 0 &&
924 		( pCrsr == 0 ||
925 	 	  pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() ||
926 		  !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) )
927     {
928         // create pam for selection
929         SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ),
930 						pTxtFrm->GetOfst() );
931         SwPosition aStartPos( *pTxtNd, aIndex );
932         SwPaM aPaM( aStartPos );
933 
934         // set PaM at cursor shell
935 		Select( aPaM );
936 
937 
938     }
939 
940     /* ->#i13955# */
941     Window * pWindow = GetWindow();
942 
943     if (pWindow != NULL)
944         pWindow->GrabFocus();
945     /* <-#i13955# */
946 }
947 
948 // --> OD 2007-01-17 #i71385#
949 bool lcl_GetBackgroundColor( Color & rColor,
950                              const SwFrm* pFrm,
951                              SwCrsrShell* pCrsrSh )
952 {
953     const SvxBrushItem* pBackgrdBrush = 0;
954     const Color* pSectionTOXColor = 0;
955     SwRect aDummyRect;
956     if ( pFrm &&
957          pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) )
958     {
959         if ( pSectionTOXColor )
960         {
961             rColor = *pSectionTOXColor;
962             return true;
963         }
964         else
965         {
966             rColor =  pBackgrdBrush->GetColor();
967             return true;
968         }
969     }
970     else if ( pCrsrSh )
971     {
972         rColor = pCrsrSh->Imp()->GetRetoucheColor();
973         return true;
974     }
975 
976     return false;
977 }
978 
979 sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground()
980                                 throw (uno::RuntimeException)
981 {
982     Color aBackgroundCol;
983 
984     if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
985     {
986         if ( aBackgroundCol.IsDark() )
987         {
988             return COL_WHITE;
989         }
990         else
991         {
992             return COL_BLACK;
993         }
994     }
995 
996     return SwAccessibleContext::getForeground();
997 }
998 
999 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
1000                                 throw (uno::RuntimeException)
1001 {
1002     Color aBackgroundCol;
1003 
1004     if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
1005     {
1006         return aBackgroundCol.GetColor();
1007     }
1008 
1009     return SwAccessibleContext::getBackground();
1010 }
1011 // <--
1012 
1013 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getImplementationName()
1014         throw( uno::RuntimeException )
1015 {
1016     return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
1017 }
1018 
1019 sal_Bool SAL_CALL SwAccessibleParagraph::supportsService(
1020 		const ::rtl::OUString& sTestServiceName)
1021     throw (uno::RuntimeException)
1022 {
1023 	return sTestServiceName.equalsAsciiL( sServiceName,
1024 										  sizeof(sServiceName)-1 ) ||
1025 		   sTestServiceName.equalsAsciiL( sAccessibleServiceName,
1026 				   						  sizeof(sAccessibleServiceName)-1 );
1027 }
1028 
1029 uno::Sequence< ::rtl::OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames()
1030         throw( uno::RuntimeException )
1031 {
1032     uno::Sequence< ::rtl::OUString > aRet(2);
1033     ::rtl::OUString* pArray = aRet.getArray();
1034     pArray[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
1035     pArray[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
1036 	return aRet;
1037 }
1038 
1039 //
1040 //=====  XInterface  =======================================================
1041 //
1042 
1043 uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType )
1044     throw (uno::RuntimeException)
1045 {
1046     uno::Any aRet;
1047     if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) )
1048     {
1049         uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity
1050         aRet <<= aAccText;
1051     }
1052     else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) )
1053     {
1054         uno::Reference<XAccessibleEditableText> aAccEditText = this;
1055         aRet <<= aAccEditText;
1056     }
1057     else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) )
1058     {
1059         uno::Reference<XAccessibleSelection> aAccSel = this;
1060         aRet <<= aAccSel;
1061     }
1062     else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) )
1063     {
1064         uno::Reference<XAccessibleHypertext> aAccHyp = this;
1065         aRet <<= aAccHyp;
1066     }
1067     // --> OD 2006-07-13 #i63870#
1068     // add interface com::sun:star:accessibility::XAccessibleTextAttributes
1069     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) )
1070     {
1071         uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
1072         aRet <<= aAccTextAttr;
1073     }
1074     // <--
1075     // --> OD 2008-06-10 #i89175#
1076     // add interface com::sun:star:accessibility::XAccessibleTextMarkup
1077     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) )
1078     {
1079         uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this;
1080         aRet <<= aAccTextMarkup;
1081     }
1082     // add interface com::sun:star:accessibility::XAccessibleMultiLineText
1083     else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) )
1084     {
1085         uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this;
1086         aRet <<= aAccMultiLineText;
1087     }
1088     // <--
1089     else
1090     {
1091         aRet = SwAccessibleContext::queryInterface(rType);
1092     }
1093 
1094     return aRet;
1095 }
1096 
1097 //====== XTypeProvider ====================================================
1098 uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException)
1099 {
1100     uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
1101 
1102 	sal_Int32 nIndex = aTypes.getLength();
1103     // --> OD 2006-07-13 #i63870#
1104     // add type accessibility::XAccessibleTextAttributes
1105     // --> OD 2008-06-10 #i89175#
1106     // add type accessibility::XAccessibleTextMarkup and accessibility::XAccessibleMultiLineText
1107     aTypes.realloc( nIndex + 6 );
1108 
1109     uno::Type* pTypes = aTypes.getArray();
1110 	pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) );
1111     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) );
1112 	pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) );
1113     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) );
1114     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) );
1115 	pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) );
1116     // <--
1117 
1118 	return aTypes;
1119 }
1120 
1121 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId()
1122         throw(uno::RuntimeException)
1123 {
1124     vos::OGuard aGuard(Application::GetSolarMutex());
1125     static uno::Sequence< sal_Int8 > aId( 16 );
1126     static sal_Bool bInit = sal_False;
1127     if(!bInit)
1128     {
1129         rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
1130         bInit = sal_True;
1131     }
1132     return aId;
1133 }
1134 
1135 
1136 //
1137 //=====  XAccesibleText  ===================================================
1138 //
1139 
1140 sal_Int32 SwAccessibleParagraph::getCaretPosition()
1141     throw (uno::RuntimeException)
1142 {
1143 	vos::OGuard aGuard(Application::GetSolarMutex());
1144 
1145 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1146 
1147     sal_Int32 nRet = GetCaretPos();
1148 	{
1149         vos::OGuard aOldCaretPosGuard( aMutex );
1150 		ASSERT( nRet == nOldCaretPos, "caret pos out of sync" );
1151 		nOldCaretPos = nRet;
1152 	}
1153 	if( -1 != nRet )
1154 	{
1155 		::vos::ORef < SwAccessibleContext > xThis( this );
1156 		GetMap()->SetCursorContext( xThis );
1157 	}
1158 
1159     return nRet;
1160 }
1161 
1162 sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
1163     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1164 {
1165 	vos::OGuard aGuard(Application::GetSolarMutex());
1166 
1167 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1168 
1169     // parameter checking
1170     sal_Int32 nLength = GetString().getLength();
1171     if ( ! IsValidPosition( nIndex, nLength ) )
1172     {
1173         throw lang::IndexOutOfBoundsException();
1174     }
1175 
1176     sal_Bool bRet = sal_False;
1177 
1178     // get cursor shell
1179     SwCrsrShell* pCrsrShell = GetCrsrShell();
1180     if( pCrsrShell != NULL )
1181     {
1182         // create pam for selection
1183         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1184         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex));
1185         SwPosition aStartPos( *pNode, aIndex );
1186         SwPaM aPaM( aStartPos );
1187 
1188         // set PaM at cursor shell
1189         bRet = Select( aPaM );
1190     }
1191 
1192     return bRet;
1193 }
1194 
1195 sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex )
1196     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1197 {
1198 	vos::OGuard aGuard(Application::GetSolarMutex());
1199 
1200 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1201 
1202     ::rtl::OUString sText( GetString() );
1203 
1204     // return character (if valid)
1205     if( IsValidChar(nIndex, sText.getLength() ) )
1206     {
1207         return sText.getStr()[nIndex];
1208     }
1209     else
1210         throw lang::IndexOutOfBoundsException();
1211 }
1212 
1213 // --> OD 2006-07-20 #i63870#
1214 // re-implement method on behalf of methods <_getDefaultAttributesImpl(..)> and
1215 // <_getRunAttributesImpl(..)>
1216 uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes(
1217     sal_Int32 nIndex,
1218     const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1219     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1220 {
1221 
1222 	vos::OGuard aGuard(Application::GetSolarMutex());
1223 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1224 
1225     const ::rtl::OUString& rText = GetString();
1226 
1227     if( ! IsValidChar( nIndex, rText.getLength() ) )
1228         throw lang::IndexOutOfBoundsException();
1229 
1230     // retrieve default character attributes
1231     tAccParaPropValMap aDefAttrSeq;
1232     _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true );
1233 
1234     // retrieved run character attributes
1235     tAccParaPropValMap aRunAttrSeq;
1236     _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1237 
1238     // merge default and run attributes
1239     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1240     PropertyValue* pValues = aValues.getArray();
1241     sal_Int32 i = 0;
1242     for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin();
1243           aDefIter != aDefAttrSeq.end();
1244           ++aDefIter )
1245     {
1246         tAccParaPropValMap::const_iterator aRunIter =
1247                                         aRunAttrSeq.find( aDefIter->first );
1248         if ( aRunIter != aRunAttrSeq.end() )
1249         {
1250             pValues[i] = aRunIter->second;
1251         }
1252         else
1253         {
1254             pValues[i] = aDefIter->second;
1255         }
1256         ++i;
1257     }
1258 
1259 //    // create a (dummy) text portion for the sole purpose of calling
1260 //    // getPropertyValues on it
1261 //    Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 );
1262 
1263 //    // get values
1264 //    Sequence<OUString> aNames = getAttributeNames();
1265 //    sal_Int32 nLength = aNames.getLength();
1266 //    Sequence<Any> aAnys( nLength );
1267 //    aAnys = xPortion->getPropertyValues( aNames );
1268 
1269 //    // copy names + anys into return sequence
1270 //    Sequence<PropertyValue> aValues( aNames.getLength() );
1271 //    const OUString* pNames = aNames.getConstArray();
1272 //    const Any* pAnys = aAnys.getConstArray();
1273 //    PropertyValue* pValues = aValues.getArray();
1274 //    for( sal_Int32 i = 0; i < nLength; i++ )
1275 //    {
1276 //        PropertyValue& rValue = pValues[i];
1277 //        rValue.Name = pNames[i];
1278 //        rValue.Value = pAnys[i];
1279 //        rValue.Handle = -1;                         // handle not supported
1280 //        rValue.State = PropertyState_DIRECT_VALUE;  // states not supported
1281 //    }
1282 
1283 //    // adjust background color if we're in a gray portion
1284 //    DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name.
1285 //                equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")),
1286 //                "Please adjust CHAR_BACK_COLOR_POS constant." );
1287 //    if( GetPortionData().IsInGrayPortion( nIndex ) )
1288 //        pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
1289 
1290     return aValues;
1291 }
1292 
1293 // --> OD 2006-07-11 #i63870#
1294 void SwAccessibleParagraph::_getDefaultAttributesImpl(
1295         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1296         tAccParaPropValMap& rDefAttrSeq,
1297         const bool bOnlyCharAttrs )
1298 {
1299     // retrieve default attributes
1300     const SwTxtNode* pTxtNode( GetTxtNode() );
1301     ::boost::scoped_ptr<SfxItemSet> pSet;
1302     if ( !bOnlyCharAttrs )
1303     {
1304         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1305                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1306                                RES_PARATR_BEGIN, RES_PARATR_END - 1,
1307                                RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1308                                0 ) );
1309     }
1310     else
1311     {
1312         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1313                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1314                                0 ) );
1315     }
1316     // --> OD 2007-11-12 #i82637#
1317     // From the perspective of the a11y API the default character attributes
1318     // are the character attributes, which are set at the paragraph style
1319     // of the paragraph. The character attributes set at the automatic paragraph
1320     // style of the paragraph are treated as run attributes.
1321 //    pTxtNode->SwCntntNode::GetAttr( *pSet );
1322     // get default paragraph attributes, if needed, and merge these into <pSet>
1323     if ( !bOnlyCharAttrs )
1324     {
1325         SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1326                              RES_PARATR_BEGIN, RES_PARATR_END - 1,
1327                              RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1328                              0 );
1329         pTxtNode->SwCntntNode::GetAttr( aParaSet );
1330         pSet->Put( aParaSet );
1331     }
1332     // get default character attributes and merge these into <pSet>
1333     ASSERT( pTxtNode->GetTxtColl(),
1334             "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" );
1335     if ( pTxtNode->GetTxtColl() )
1336     {
1337         SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1338                              RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1339                              0 );
1340         aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() );
1341         pSet->Put( aCharSet );
1342     }
1343     // <--
1344 
1345     // build-up sequence containing the run attributes <rDefAttrSeq>
1346     tAccParaPropValMap aDefAttrSeq;
1347     {
1348         const SfxItemPropertyMap* pPropMap =
1349                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1350         PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
1351         PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1352         while ( aPropIt != aPropertyEntries.end() )
1353         {
1354             const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID );
1355             if ( pItem )
1356             {
1357                 uno::Any aVal;
1358                 pItem->QueryValue( aVal, aPropIt->nMemberId );
1359 
1360                 PropertyValue rPropVal;
1361                 rPropVal.Name = aPropIt->sName;
1362                 rPropVal.Value = aVal;
1363                 rPropVal.Handle = -1;
1364                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1365 
1366                 aDefAttrSeq[rPropVal.Name] = rPropVal;
1367             }
1368             ++aPropIt;
1369         }
1370 
1371         // --> OD 2007-01-15 #i72800#
1372         // add property value entry for the paragraph style
1373         if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() )
1374         {
1375             const ::rtl::OUString sParaStyleName =
1376                     ::rtl::OUString::createFromAscii(
1377                             GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName );
1378             if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() )
1379             {
1380                 PropertyValue rPropVal;
1381                 rPropVal.Name = sParaStyleName;
1382                 uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) );
1383                 rPropVal.Value = aVal;
1384                 rPropVal.Handle = -1;
1385                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1386 
1387                 aDefAttrSeq[rPropVal.Name] = rPropVal;
1388             }
1389         }
1390         // <--
1391 
1392         // --> OD 2007-01-15 #i73371#
1393         // resolve value text::WritingMode2::PAGE of property value entry WritingMode
1394         if ( !bOnlyCharAttrs && GetFrm() )
1395         {
1396             const ::rtl::OUString sWritingMode =
1397                     ::rtl::OUString::createFromAscii(
1398                             GetPropName( UNO_NAME_WRITING_MODE ).pName );
1399             tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode );
1400             if ( aIter != aDefAttrSeq.end() )
1401             {
1402                 PropertyValue rPropVal( aIter->second );
1403                 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
1404                 if ( nVal == text::WritingMode2::PAGE )
1405                 {
1406                     const SwFrm* pUpperFrm( GetFrm()->GetUpper() );
1407                     while ( pUpperFrm )
1408                     {
1409                         if ( pUpperFrm->GetType() &
1410                                ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) )
1411                         {
1412                             if ( pUpperFrm->IsVertical() )
1413                             {
1414                                 nVal = text::WritingMode2::TB_RL;
1415                             }
1416                             else if ( pUpperFrm->IsRightToLeft() )
1417                             {
1418                                 nVal = text::WritingMode2::RL_TB;
1419                             }
1420                             else
1421                             {
1422                                 nVal = text::WritingMode2::LR_TB;
1423                             }
1424                             rPropVal.Value <<= nVal;
1425                             aDefAttrSeq[rPropVal.Name] = rPropVal;
1426                             break;
1427                         }
1428 
1429                         if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) )
1430                         {
1431                             pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm();
1432                         }
1433                         else
1434                         {
1435                             pUpperFrm = pUpperFrm->GetUpper();
1436                         }
1437                     }
1438                 }
1439             }
1440         }
1441         // <--
1442     }
1443 
1444     if ( aRequestedAttributes.getLength() == 0 )
1445     {
1446         rDefAttrSeq = aDefAttrSeq;
1447     }
1448     else
1449     {
1450         const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1451         const sal_Int32 nLength = aRequestedAttributes.getLength();
1452         for( sal_Int32 i = 0; i < nLength; ++i )
1453         {
1454             tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] );
1455             if ( aIter != aDefAttrSeq.end() )
1456             {
1457                 rDefAttrSeq[ aIter->first ] = aIter->second;
1458             }
1459         }
1460     }
1461 }
1462 
1463 uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
1464         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1465         throw ( uno::RuntimeException )
1466 {
1467     vos::OGuard aGuard(Application::GetSolarMutex());
1468     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1469 
1470     tAccParaPropValMap aDefAttrSeq;
1471     _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
1472 
1473     // --> OD 2010-03-08 #i92233#
1474     static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "MMToPixelRatio" ) );
1475     bool bProvideMMToPixelRatio( false );
1476     {
1477         if ( aRequestedAttributes.getLength() == 0 )
1478         {
1479             bProvideMMToPixelRatio = true;
1480         }
1481         else
1482         {
1483             const rtl::OUString* aRequestedAttrIter =
1484                   ::std::find( ::comphelper::stl_begin( aRequestedAttributes ),
1485                                ::comphelper::stl_end( aRequestedAttributes ),
1486                                sMMToPixelRatio );
1487             if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) )
1488             {
1489                 bProvideMMToPixelRatio = true;
1490             }
1491         }
1492     }
1493     // <--
1494 
1495     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() +
1496                                             ( bProvideMMToPixelRatio ? 1 : 0 ) );
1497     PropertyValue* pValues = aValues.getArray();
1498     sal_Int32 i = 0;
1499     for ( tAccParaPropValMap::const_iterator aIter  = aDefAttrSeq.begin();
1500           aIter != aDefAttrSeq.end();
1501           ++aIter )
1502     {
1503         pValues[i] = aIter->second;
1504         ++i;
1505     }
1506 
1507     // --> OD 2010-03-08 #i92233#
1508     if ( bProvideMMToPixelRatio )
1509     {
1510         PropertyValue rPropVal;
1511         rPropVal.Name = sMMToPixelRatio;
1512         const Size a100thMMSize( 1000, 1000 );
1513         const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize );
1514         const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width();
1515         rPropVal.Value = uno::makeAny( fRatio );
1516         rPropVal.Handle = -1;
1517         rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1518         pValues[ aValues.getLength() - 1 ] = rPropVal;
1519     }
1520     // <--
1521 
1522     return aValues;
1523 }
1524 
1525 void SwAccessibleParagraph::_getRunAttributesImpl(
1526         const sal_Int32 nIndex,
1527         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1528         tAccParaPropValMap& rRunAttrSeq )
1529 {
1530     // create PaM for character at position <nIndex>
1531     SwPaM* pPaM( 0 );
1532     {
1533         const SwTxtNode* pTxtNode( GetTxtNode() );
1534         SwPosition* pStartPos = new SwPosition( *pTxtNode );
1535         pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) );
1536         SwPosition* pEndPos = new SwPosition( *pTxtNode );
1537         pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) );
1538 
1539         pPaM = new SwPaM( *pStartPos, *pEndPos );
1540 
1541         delete pStartPos;
1542         delete pEndPos;
1543     }
1544 
1545     // retrieve character attributes for the created PaM <pPaM>
1546     SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(),
1547                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1548                      0 );
1549     // --> OD 2007-11-12 #i82637#
1550     // From the perspective of the a11y API the character attributes, which
1551     // are set at the automatic paragraph style of the paragraph are treated
1552     // as run attributes.
1553 //    SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True );
1554     // get character attributes from automatic paragraph style and merge these into <aSet>
1555     {
1556         const SwTxtNode* pTxtNode( GetTxtNode() );
1557         if ( pTxtNode->HasSwAttrSet() )
1558         {
1559             SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(),
1560                                                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1561                                                      0 );
1562             aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False );
1563             aSet.Put( aAutomaticParaStyleCharAttrs );
1564         }
1565     }
1566     // get character attributes at <pPaM> and merge these into <aSet>
1567     {
1568         SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(),
1569                                     RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1570                                     0 );
1571         SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True);
1572         aSet.Put( aCharAttrsAtPaM );
1573     }
1574     // <--
1575 
1576     // build-up sequence containing the run attributes <rRunAttrSeq>
1577     {
1578         tAccParaPropValMap aRunAttrSeq;
1579         {
1580             // --> OD 2007-11-12 #i82637#
1581             tAccParaPropValMap aDefAttrSeq;
1582             uno::Sequence< ::rtl::OUString > aDummy;
1583             _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true );
1584             // <--
1585 
1586             const SfxItemPropertyMap* pPropMap =
1587                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1588             PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
1589             PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1590             while ( aPropIt != aPropertyEntries.end() )
1591             {
1592                 const SfxPoolItem* pItem( 0 );
1593                 // --> OD 2007-11-12 #i82637#
1594                 // Found character attributes, whose value equals the value of
1595                 // the corresponding default character attributes, are excluded.
1596                 if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET )
1597                 {
1598                     uno::Any aVal;
1599                     pItem->QueryValue( aVal, aPropIt->nMemberId );
1600 
1601                     PropertyValue rPropVal;
1602                     rPropVal.Name = aPropIt->sName;
1603                     rPropVal.Value = aVal;
1604                     rPropVal.Handle = -1;
1605                     rPropVal.State = PropertyState_DIRECT_VALUE;
1606 
1607                     tAccParaPropValMap::const_iterator aDefIter =
1608                                             aDefAttrSeq.find( rPropVal.Name );
1609                     if ( aDefIter == aDefAttrSeq.end() ||
1610                          rPropVal.Value != aDefIter->second.Value )
1611                     {
1612                         aRunAttrSeq[rPropVal.Name] = rPropVal;
1613                     }
1614                 }
1615 
1616                 ++aPropIt;
1617             }
1618         }
1619 
1620         if ( aRequestedAttributes.getLength() == 0 )
1621         {
1622             rRunAttrSeq = aRunAttrSeq;
1623         }
1624         else
1625         {
1626             const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1627             const sal_Int32 nLength = aRequestedAttributes.getLength();
1628             for( sal_Int32 i = 0; i < nLength; ++i )
1629             {
1630                 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1631                 if ( aIter != aRunAttrSeq.end() )
1632                 {
1633                     rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1634                 }
1635             }
1636         }
1637     }
1638 
1639     delete pPaM;
1640 }
1641 
1642 uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
1643         sal_Int32 nIndex,
1644         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1645         throw ( lang::IndexOutOfBoundsException,
1646                 uno::RuntimeException )
1647 {
1648     vos::OGuard aGuard(Application::GetSolarMutex());
1649     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1650 
1651     {
1652         const ::rtl::OUString& rText = GetString();
1653         if ( !IsValidChar( nIndex, rText.getLength() ) )
1654         {
1655             throw lang::IndexOutOfBoundsException();
1656         }
1657     }
1658 
1659     tAccParaPropValMap aRunAttrSeq;
1660     _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1661 
1662     uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() );
1663     PropertyValue* pValues = aValues.getArray();
1664     sal_Int32 i = 0;
1665     for ( tAccParaPropValMap::const_iterator aIter  = aRunAttrSeq.begin();
1666           aIter != aRunAttrSeq.end();
1667           ++aIter )
1668     {
1669         pValues[i] = aIter->second;
1670         ++i;
1671     }
1672 
1673     return aValues;
1674 }
1675 // <--
1676 
1677 awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
1678     sal_Int32 nIndex )
1679     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1680 {
1681 	vos::OGuard aGuard(Application::GetSolarMutex());
1682 
1683 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1684 
1685 
1686     /*  #i12332# The position after the string needs special treatment.
1687         IsValidChar -> IsValidPosition
1688     */
1689     if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
1690         throw lang::IndexOutOfBoundsException();
1691 
1692     /*  #i12332#  */
1693     sal_Bool bBehindText = sal_False;
1694     if ( nIndex == GetString().getLength() )
1695         bBehindText = sal_True;
1696 
1697     // get model position & prepare GetCharRect() arguments
1698     SwCrsrMoveState aMoveState;
1699     aMoveState.bRealHeight = sal_True;
1700     aMoveState.bRealWidth = sal_True;
1701     SwSpecialPos aSpecialPos;
1702     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1703 
1704     sal_uInt16 nPos = 0;
1705 
1706     /*  #i12332# FillSpecialPos does not accept nIndex ==
1707          GetString().getLength(). In that case nPos is set to the
1708          length of the string in the core. This way GetCharRect
1709          returns the rectangle for a cursor at the end of the
1710          paragraph. */
1711     if (bBehindText)
1712     {
1713         nPos = pNode->GetTxt().Len();
1714     }
1715     else
1716         nPos = GetPortionData().FillSpecialPos
1717             (nIndex, aSpecialPos, aMoveState.pSpecialPos );
1718 
1719     // call GetCharRect
1720     SwRect aCoreRect;
1721     SwIndex aIndex( pNode, nPos );
1722     SwPosition aPosition( *pNode, aIndex );
1723     GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
1724 
1725     // translate core coordinates into accessibility coordinates
1726 	Window *pWin = GetWindow();
1727 	CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1728 
1729 	Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
1730     SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
1731 
1732 	Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
1733 	aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
1734 
1735     // convert into AWT Rectangle
1736     return awt::Rectangle(
1737         aScreenRect.Left(), aScreenRect.Top(),
1738         aScreenRect.GetWidth(), aScreenRect.GetHeight() );
1739 }
1740 
1741 sal_Int32 SwAccessibleParagraph::getCharacterCount()
1742     throw (uno::RuntimeException)
1743 {
1744 	vos::OGuard aGuard(Application::GetSolarMutex());
1745 
1746 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1747 
1748     return GetString().getLength();
1749 }
1750 
1751 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
1752     throw (uno::RuntimeException)
1753 {
1754 	vos::OGuard aGuard(Application::GetSolarMutex());
1755 
1756 
1757 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1758 
1759     // construct SwPosition (where GetCrsrOfst() will put the result into)
1760     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1761     SwIndex aIndex( pNode, 0);
1762     SwPosition aPos( *pNode, aIndex );
1763 
1764     // construct Point (translate into layout coordinates)
1765 	Window *pWin = GetWindow();
1766 	CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1767     Point aPoint( rPoint.X, rPoint.Y );
1768     SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root
1769 	Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
1770 	aPoint.X() += aPixPos.X();
1771 	aPoint.Y() += aPixPos.Y();
1772     MapMode aMapMode = pWin->GetMapMode();
1773 	Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
1774 	if( !aLogBounds.IsInside( aCorePoint ) )
1775     {
1776         /* #i12332# rPoint is may also be in rectangle returned by
1777             getCharacterBounds(getCharacterCount() */
1778 
1779         awt::Rectangle aRectEndPos =
1780             getCharacterBounds(getCharacterCount());
1781 
1782         if (rPoint.X - aRectEndPos.X >= 0 &&
1783             rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
1784             rPoint.Y - aRectEndPos.Y >= 0 &&
1785             rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
1786             return getCharacterCount();
1787 
1788 		return -1;
1789     }
1790 
1791     // ask core for position
1792     DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
1793     DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
1794     const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
1795     SwCrsrMoveState aMoveState;
1796     aMoveState.bPosMatchesBounds = sal_True;
1797     sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState );
1798 
1799     SwIndex aCntntIdx = aPos.nContent;
1800     const xub_StrLen nIndex = aCntntIdx.GetIndex();
1801     if ( nIndex > 0 )
1802     {
1803         SwRect aResultRect;
1804         pFrm->GetCharRect( aResultRect, aPos );
1805         bool bVert = pFrm->IsVertical();
1806         bool bR2L = pFrm->IsRightToLeft();
1807 
1808         if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) ||
1809              ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) ||
1810              ( bR2L  && aResultRect.Right()   < aCorePoint.X()) )
1811         {
1812             SwIndex aIdxPrev( pNode, nIndex - 1);
1813             SwPosition aPosPrev( *pNode, aIdxPrev );
1814             SwRect aResultRectPrev;
1815             pFrm->GetCharRect( aResultRectPrev, aPosPrev );
1816             if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ||
1817                  ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) ||
1818                  (  bR2L && aResultRectPrev.Right()   > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) )
1819                 aPos = aPosPrev;
1820         }
1821     }
1822 
1823     return bSuccess ?
1824         GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() )
1825         : -1L;
1826 }
1827 
1828 ::rtl::OUString SwAccessibleParagraph::getSelectedText()
1829     throw (uno::RuntimeException)
1830 {
1831     vos::OGuard aGuard(Application::GetSolarMutex());
1832 
1833 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1834 
1835     sal_Int32 nStart, nEnd;
1836     sal_Bool bSelected = GetSelection( nStart, nEnd );
1837     return bSelected
1838            ? GetString().copy( nStart, nEnd - nStart )
1839            : ::rtl::OUString();
1840 }
1841 
1842 sal_Int32 SwAccessibleParagraph::getSelectionStart()
1843     throw (uno::RuntimeException)
1844 {
1845 	vos::OGuard aGuard(Application::GetSolarMutex());
1846 
1847 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1848 
1849     sal_Int32 nStart, nEnd;
1850     GetSelection( nStart, nEnd );
1851     return nStart;
1852 }
1853 
1854 sal_Int32 SwAccessibleParagraph::getSelectionEnd()
1855     throw (uno::RuntimeException)
1856 {
1857 	vos::OGuard aGuard(Application::GetSolarMutex());
1858 
1859 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1860 
1861     sal_Int32 nStart, nEnd;
1862     GetSelection( nStart, nEnd );
1863     return nEnd;
1864 }
1865 
1866 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1867     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1868 {
1869 	vos::OGuard aGuard(Application::GetSolarMutex());
1870 
1871 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1872 
1873     // parameter checking
1874     sal_Int32 nLength = GetString().getLength();
1875     if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
1876     {
1877         throw lang::IndexOutOfBoundsException();
1878     }
1879 
1880     sal_Bool bRet = sal_False;
1881 
1882     // get cursor shell
1883     SwCrsrShell* pCrsrShell = GetCrsrShell();
1884     if( pCrsrShell != NULL )
1885     {
1886         // create pam for selection
1887         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1888         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex));
1889         SwPosition aStartPos( *pNode, aIndex );
1890         SwPaM aPaM( aStartPos );
1891         aPaM.SetMark();
1892         aPaM.GetPoint()->nContent =
1893             GetPortionData().GetModelPosition(nEndIndex);
1894 
1895         // set PaM at cursor shell
1896         bRet = Select( aPaM );
1897     }
1898 
1899     return bRet;
1900 }
1901 
1902 ::rtl::OUString SwAccessibleParagraph::getText()
1903     throw (uno::RuntimeException)
1904 {
1905 	vos::OGuard aGuard(Application::GetSolarMutex());
1906 
1907 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1908 
1909     return GetString();
1910 }
1911 
1912 ::rtl::OUString SwAccessibleParagraph::getTextRange(
1913     sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1914     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1915 {
1916 	vos::OGuard aGuard(Application::GetSolarMutex());
1917 
1918 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1919 
1920     ::rtl::OUString sText( GetString() );
1921 
1922     if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
1923     {
1924         OrderRange( nStartIndex, nEndIndex );
1925         return sText.copy(nStartIndex, nEndIndex-nStartIndex );
1926     }
1927     else
1928         throw lang::IndexOutOfBoundsException();
1929 }
1930 
1931 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1932 {
1933 	vos::OGuard aGuard(Application::GetSolarMutex());
1934 
1935 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1936 
1937     /*accessibility::*/TextSegment aResult;
1938     aResult.SegmentStart = -1;
1939     aResult.SegmentEnd = -1;
1940 
1941     const ::rtl::OUString rText = GetString();
1942     // implement the silly specification that first position after
1943     // text must return an empty string, rather than throwing an
1944     // IndexOutOfBoundsException, except for LINE, where the last
1945 	// line is returned
1946     if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
1947 		return aResult;
1948 
1949     // with error checking
1950     i18n::Boundary aBound;
1951     sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1952 
1953     DBG_ASSERT( aBound.startPos >= 0,               "illegal boundary" );
1954     DBG_ASSERT( aBound.startPos <= aBound.endPos,   "illegal boundary" );
1955 
1956     // return word (if present)
1957     if ( bWord )
1958     {
1959     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1960     	aResult.SegmentStart = aBound.startPos;
1961     	aResult.SegmentEnd = aBound.endPos;
1962     }
1963 
1964     return aResult;
1965 }
1966 
1967 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1968 {
1969 	vos::OGuard aGuard(Application::GetSolarMutex());
1970 
1971 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1972 
1973     const ::rtl::OUString rText = GetString();
1974 
1975     /*accessibility::*/TextSegment aResult;
1976     aResult.SegmentStart = -1;
1977     aResult.SegmentEnd = -1;
1978 
1979     // get starting pos
1980     i18n::Boundary aBound;
1981     if (nIndex ==  rText.getLength())
1982         aBound.startPos = aBound.endPos = nIndex;
1983     else
1984     {
1985         sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
1986 
1987         if ( ! bTmp )
1988             aBound.startPos = aBound.endPos = nIndex;
1989     }
1990 
1991     // now skip to previous word
1992     sal_Bool bWord = sal_False;
1993     while( !bWord )
1994     {
1995         nIndex = min( nIndex, aBound.startPos ) - 1;
1996         if( nIndex >= 0 )
1997             bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1998         else
1999             break;  // exit if beginning of string is reached
2000     }
2001 
2002     if ( bWord )
2003     {
2004     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2005     	aResult.SegmentStart = aBound.startPos;
2006     	aResult.SegmentEnd = aBound.endPos;
2007     };
2008     return aResult;
2009 }
2010 
2011 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
2012 {
2013 	vos::OGuard aGuard(Application::GetSolarMutex());
2014 
2015 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2016 
2017     /*accessibility::*/TextSegment aResult;
2018     aResult.SegmentStart = -1;
2019     aResult.SegmentEnd = -1;
2020     const ::rtl::OUString rText = GetString();
2021 
2022     // implement the silly specification that first position after
2023     // text must return an empty string, rather than throwing an
2024     // IndexOutOfBoundsException
2025     if( nIndex == rText.getLength() )
2026         return aResult;
2027 
2028 
2029     // get first word, then skip to next word
2030     i18n::Boundary aBound;
2031     GetTextBoundary( aBound, rText, nIndex, nTextType );
2032     sal_Bool bWord = sal_False;
2033     while( !bWord )
2034     {
2035         nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
2036         if( nIndex < rText.getLength() )
2037             bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2038         else
2039             break;  // exit if end of string is reached
2040     }
2041 
2042     if ( bWord )
2043     {
2044     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2045     	aResult.SegmentStart = aBound.startPos;
2046     	aResult.SegmentEnd = aBound.endPos;
2047     }
2048     return aResult;
2049 }
2050 
2051 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2052     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2053 {
2054 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2055 	vos::OGuard aGuard(Application::GetSolarMutex());
2056 
2057     // select and copy (through dispatch mechanism)
2058     setSelection( nStartIndex, nEndIndex );
2059     ExecuteAtViewShell( SID_COPY );
2060     return sal_True;
2061 }
2062 
2063 
2064 //
2065 //=====  XAccesibleEditableText  ==========================================
2066 //
2067 
2068 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2069     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2070 {
2071 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2072 	vos::OGuard aGuard(Application::GetSolarMutex());
2073 
2074 	if( !IsEditableState() )
2075 		return sal_False;
2076 
2077     // select and cut (through dispatch mechanism)
2078     setSelection( nStartIndex, nEndIndex );
2079     ExecuteAtViewShell( SID_CUT );
2080     return sal_True;
2081 }
2082 
2083 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
2084     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2085 {
2086 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2087 	vos::OGuard aGuard(Application::GetSolarMutex());
2088 
2089 	if( !IsEditableState() )
2090 		return sal_False;
2091 
2092     // select and paste (through dispatch mechanism)
2093     setSelection( nIndex, nIndex );
2094     ExecuteAtViewShell( SID_PASTE );
2095     return sal_True;
2096 }
2097 
2098 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2099     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2100 {
2101     return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() );
2102 }
2103 
2104 sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex )
2105     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2106 {
2107     return replaceText( nIndex, nIndex, sText );
2108 }
2109 
2110 sal_Bool SwAccessibleParagraph::replaceText(
2111     sal_Int32 nStartIndex, sal_Int32 nEndIndex,
2112     const ::rtl::OUString& sReplacement )
2113     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2114 {
2115 	vos::OGuard aGuard(Application::GetSolarMutex());
2116 
2117 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2118 
2119     const ::rtl::OUString& rText = GetString();
2120 
2121     if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2122     {
2123 		if( !IsEditableState() )
2124 			return sal_False;
2125 
2126         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2127 
2128         // translate positions
2129         sal_uInt16 nStart, nEnd;
2130         sal_Bool bSuccess = GetPortionData().GetEditableRange(
2131                                         nStartIndex, nEndIndex, nStart, nEnd );
2132 
2133         // edit only if the range is editable
2134         if( bSuccess )
2135         {
2136             // create SwPosition for nStartIndex
2137             SwIndex aIndex( pNode, nStart );
2138             SwPosition aStartPos( *pNode, aIndex );
2139 
2140             // create SwPosition for nEndIndex
2141             SwPosition aEndPos( aStartPos );
2142             aEndPos.nContent = nEnd;
2143 
2144             // now create XTextRange as helper and set string
2145             const uno::Reference<text::XTextRange> xRange(
2146                 SwXTextRange::CreateXTextRange(
2147                     *pNode->GetDoc(), aStartPos, &aEndPos));
2148             xRange->setString(sReplacement);
2149 
2150             // delete portion data
2151             ClearPortionData();
2152         }
2153 
2154         return bSuccess;
2155     }
2156     else
2157         throw lang::IndexOutOfBoundsException();
2158 }
2159 
2160 struct IndexCompare
2161 {
2162     const PropertyValue* pValues;
2163     IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
2164     bool operator() ( const sal_Int32& a, const sal_Int32& b ) const
2165     {
2166         return (pValues[a].Name < pValues[b].Name) ? true : false;
2167     }
2168 };
2169 
2170 
2171 sal_Bool SwAccessibleParagraph::setAttributes(
2172     sal_Int32 nStartIndex,
2173     sal_Int32 nEndIndex,
2174     const uno::Sequence<PropertyValue>& rAttributeSet )
2175     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2176 {
2177 	vos::OGuard aGuard(Application::GetSolarMutex());
2178 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2179 
2180     const ::rtl::OUString& rText = GetString();
2181 
2182     if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2183         throw lang::IndexOutOfBoundsException();
2184 
2185 	if( !IsEditableState() )
2186 		return sal_False;
2187 
2188 
2189     // create a (dummy) text portion for the sole purpose of calling
2190     // setPropertyValue on it
2191     uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
2192                                                               nEndIndex );
2193 
2194     // build sorted index array
2195     sal_Int32 nLength = rAttributeSet.getLength();
2196     const PropertyValue* pPairs = rAttributeSet.getConstArray();
2197     sal_Int32* pIndices = new sal_Int32[nLength];
2198     sal_Int32 i;
2199     for( i = 0; i < nLength; i++ )
2200         pIndices[i] = i;
2201     sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
2202 
2203     // create sorted sequences accoring to index array
2204     uno::Sequence< ::rtl::OUString > aNames( nLength );
2205     ::rtl::OUString* pNames = aNames.getArray();
2206     uno::Sequence< uno::Any > aValues( nLength );
2207     uno::Any* pValues = aValues.getArray();
2208     for( i = 0; i < nLength; i++ )
2209     {
2210         const PropertyValue& rVal = pPairs[pIndices[i]];
2211         pNames[i]  = rVal.Name;
2212         pValues[i] = rVal.Value;
2213     }
2214     delete[] pIndices;
2215 
2216     // now set the values
2217     sal_Bool bRet = sal_True;
2218     try
2219     {
2220         xPortion->setPropertyValues( aNames, aValues );
2221     }
2222     catch( UnknownPropertyException e )
2223     {
2224         // error handling through return code!
2225         bRet = sal_False;
2226     }
2227 
2228     return bRet;
2229 }
2230 
2231 sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText )
2232     throw (uno::RuntimeException)
2233 {
2234     return replaceText(0, GetString().getLength(), sText);
2235 }
2236 
2237 //=====  XAccessibleSelection  ============================================
2238 
2239 void SwAccessibleParagraph::selectAccessibleChild(
2240     sal_Int32 nChildIndex )
2241     throw ( lang::IndexOutOfBoundsException,
2242             uno::RuntimeException )
2243 {
2244 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2245 
2246     aSelectionHelper.selectAccessibleChild(nChildIndex);
2247 }
2248 
2249 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
2250     sal_Int32 nChildIndex )
2251     throw ( lang::IndexOutOfBoundsException,
2252             uno::RuntimeException )
2253 {
2254 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2255 
2256     return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
2257 }
2258 
2259 void SwAccessibleParagraph::clearAccessibleSelection(  )
2260     throw ( uno::RuntimeException )
2261 {
2262 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2263 
2264     aSelectionHelper.clearAccessibleSelection();
2265 }
2266 
2267 void SwAccessibleParagraph::selectAllAccessibleChildren(  )
2268     throw ( uno::RuntimeException )
2269 {
2270 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2271 
2272     aSelectionHelper.selectAllAccessibleChildren();
2273 }
2274 
2275 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount(  )
2276     throw ( uno::RuntimeException )
2277 {
2278 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2279 
2280     return aSelectionHelper.getSelectedAccessibleChildCount();
2281 }
2282 
2283 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
2284     sal_Int32 nSelectedChildIndex )
2285     throw ( lang::IndexOutOfBoundsException,
2286             uno::RuntimeException)
2287 {
2288 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2289 
2290     return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
2291 }
2292 
2293 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
2294 void SwAccessibleParagraph::deselectAccessibleChild(
2295     sal_Int32 nChildIndex )
2296     throw ( lang::IndexOutOfBoundsException,
2297             uno::RuntimeException )
2298 {
2299 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2300 
2301     aSelectionHelper.deselectAccessibleChild( nChildIndex );
2302 }
2303 
2304 //=====  XAccessibleHypertext  ============================================
2305 
2306 class SwHyperlinkIter_Impl
2307 {
2308 	const SwpHints *pHints;
2309 	xub_StrLen nStt;
2310 	xub_StrLen nEnd;
2311 	sal_uInt16 nPos;
2312 
2313 public:
2314 	SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm );
2315 	const SwTxtAttr *next();
2316 	sal_uInt16 getCurrHintPos() const { return nPos-1; }
2317 
2318 	xub_StrLen startIdx() const { return nStt; }
2319 	xub_StrLen endIdx() const { return nEnd; }
2320 };
2321 
2322 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) :
2323 	pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ),
2324 	nStt( pTxtFrm->GetOfst() ),
2325 	nPos( 0 )
2326 {
2327 	const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow();
2328 	nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len();
2329 }
2330 
2331 const SwTxtAttr *SwHyperlinkIter_Impl::next()
2332 {
2333 	const SwTxtAttr *pAttr = 0;
2334 	if( pHints )
2335 	{
2336 		while( !pAttr && nPos < pHints->Count() )
2337 		{
2338 			const SwTxtAttr *pHt = (*pHints)[nPos];
2339 			if( RES_TXTATR_INETFMT == pHt->Which() )
2340 			{
2341 				xub_StrLen nHtStt = *pHt->GetStart();
2342 				xub_StrLen nHtEnd = *pHt->GetAnyEnd();
2343 				if( nHtEnd > nHtStt &&
2344 					( (nHtStt >= nStt && nHtStt < nEnd) ||
2345 					  (nHtEnd > nStt && nHtEnd <= nEnd) ) )
2346 				{
2347 					pAttr = pHt;
2348 				}
2349 			}
2350 			++nPos;
2351 		}
2352 	}
2353 
2354 	return pAttr;
2355 };
2356 
2357 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
2358     throw (uno::RuntimeException)
2359 {
2360 	vos::OGuard aGuard(Application::GetSolarMutex());
2361 
2362 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
2363 
2364 	sal_Int32 nCount = 0;
2365     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2366 //    if( !IsEditableState() )
2367     // <--
2368 	{
2369 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2370 		SwHyperlinkIter_Impl aIter( pTxtFrm );
2371 		while( aIter.next() )
2372 			nCount++;
2373 	}
2374 
2375 	return nCount;
2376 }
2377 
2378 uno::Reference< XAccessibleHyperlink > SAL_CALL
2379 	SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
2380     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2381 {
2382 	vos::OGuard aGuard(Application::GetSolarMutex());
2383 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
2384 
2385     uno::Reference< XAccessibleHyperlink > xRet;
2386 
2387     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2388 //    if( !IsEditableState() )
2389     // <--
2390 	{
2391 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2392 		SwHyperlinkIter_Impl aHIter( pTxtFrm );
2393 		while( nLinkIndex-- )
2394 			aHIter.next();
2395 
2396 		const SwTxtAttr *pHt = aHIter.next();
2397 		if( pHt )
2398 		{
2399 			if( !pHyperTextData )
2400 				pHyperTextData = new SwAccessibleHyperTextData;
2401 			SwAccessibleHyperTextData::iterator aIter =
2402 				pHyperTextData ->find( pHt );
2403 			if( aIter != pHyperTextData->end() )
2404 			{
2405 				xRet = (*aIter).second;
2406 			}
2407 			if( !xRet.is() )
2408 			{
2409 				sal_Int32 nHStt= GetPortionData().GetAccessiblePosition(
2410 								max( aHIter.startIdx(), *pHt->GetStart() ) );
2411 				sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition(
2412 								min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
2413 				xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
2414 												  this, nHStt, nHEnd );
2415 				if( aIter != pHyperTextData->end() )
2416 				{
2417 					(*aIter).second = xRet;
2418 				}
2419 				else
2420 				{
2421 					SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
2422 					pHyperTextData->insert( aEntry );
2423 				}
2424 			}
2425 		}
2426 	}
2427 
2428 	if( !xRet.is() )
2429         throw lang::IndexOutOfBoundsException();
2430 
2431 	return xRet;
2432 }
2433 
2434 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
2435     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2436 {
2437 	vos::OGuard aGuard(Application::GetSolarMutex());
2438 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
2439 
2440     // parameter checking
2441     sal_Int32 nLength = GetString().getLength();
2442     if ( ! IsValidPosition( nCharIndex, nLength ) )
2443     {
2444         throw lang::IndexOutOfBoundsException();
2445     }
2446 
2447 	sal_Int32 nRet = -1;
2448     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2449 //    if( !IsEditableState() )
2450     // <--
2451 	{
2452 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2453 		SwHyperlinkIter_Impl aHIter( pTxtFrm );
2454 
2455 		xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex );
2456 		sal_Int32 nPos = 0;
2457 		const SwTxtAttr *pHt = aHIter.next();
2458 		while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) )
2459 		{
2460 			pHt = aHIter.next();
2461 			nPos++;
2462 		}
2463 
2464 		if( pHt )
2465 			nRet = nPos;
2466 
2467 	}
2468 
2469 	return nRet;
2470 }
2471 
2472 // --> OD 2008-05-26 #i71360#
2473 // --> OD 2010-02-22 #i108125# - adjustments for change tracking text markup
2474 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
2475                                         throw (lang::IllegalArgumentException,
2476                                                uno::RuntimeException)
2477 {
2478     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2479     switch ( nTextMarkupType )
2480     {
2481         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2482         case text::TextMarkupType::TRACK_CHANGE_DELETION:
2483         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2484         {
2485             pTextMarkupHelper.reset( new SwTextMarkupHelper(
2486                 GetPortionData(),
2487                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2488         }
2489         break;
2490         default:
2491         {
2492             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2493         }
2494     }
2495 
2496     return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType );
2497 }
2498 
2499 /*accessibility::*/TextSegment SAL_CALL
2500         SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
2501                                               sal_Int32 nTextMarkupType )
2502                                         throw (lang::IndexOutOfBoundsException,
2503                                                lang::IllegalArgumentException,
2504                                                uno::RuntimeException)
2505 {
2506     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2507     switch ( nTextMarkupType )
2508     {
2509         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2510         case text::TextMarkupType::TRACK_CHANGE_DELETION:
2511         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2512         {
2513             pTextMarkupHelper.reset( new SwTextMarkupHelper(
2514                 GetPortionData(),
2515                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2516         }
2517         break;
2518         default:
2519         {
2520             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2521         }
2522     }
2523 
2524     return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
2525 }
2526 
2527 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
2528         SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
2529                                                      sal_Int32 nTextMarkupType )
2530                                         throw (lang::IndexOutOfBoundsException,
2531                                                lang::IllegalArgumentException,
2532                                                uno::RuntimeException)
2533 {
2534     // parameter checking
2535     const sal_Int32 nLength = GetString().getLength();
2536     if ( ! IsValidPosition( nCharIndex, nLength ) )
2537     {
2538         throw lang::IndexOutOfBoundsException();
2539     }
2540 
2541     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2542     switch ( nTextMarkupType )
2543     {
2544         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2545         case text::TextMarkupType::TRACK_CHANGE_DELETION:
2546         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2547         {
2548             pTextMarkupHelper.reset( new SwTextMarkupHelper(
2549                 GetPortionData(),
2550                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2551         }
2552         break;
2553         default:
2554         {
2555             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2556         }
2557     }
2558 
2559     return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
2560 }
2561 // <--
2562 
2563 // --> OD 2008-05-29 #i89175#
2564 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
2565                                         throw (lang::IndexOutOfBoundsException,
2566                                                uno::RuntimeException)
2567 {
2568     // parameter checking
2569     const sal_Int32 nLength = GetString().getLength();
2570     if ( ! IsValidPosition( nIndex, nLength ) )
2571     {
2572         throw lang::IndexOutOfBoundsException();
2573     }
2574 
2575     const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
2576     return nLineNo;
2577 }
2578 
2579 /*accessibility::*/TextSegment SAL_CALL
2580         SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
2581                                         throw (lang::IndexOutOfBoundsException,
2582                                                uno::RuntimeException)
2583 {
2584     // parameter checking
2585     if ( nLineNo < 0 ||
2586          nLineNo >= GetPortionData().GetLineCount() )
2587     {
2588         throw lang::IndexOutOfBoundsException();
2589     }
2590 
2591     i18n::Boundary aLineBound;
2592     GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2593 
2594     /*accessibility::*/TextSegment aTextAtLine;
2595     const ::rtl::OUString rText = GetString();
2596     aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
2597                                           aLineBound.endPos - aLineBound.startPos );
2598     aTextAtLine.SegmentStart = aLineBound.startPos;
2599     aTextAtLine.SegmentEnd = aLineBound.endPos;
2600 
2601     return aTextAtLine;
2602 }
2603 
2604 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
2605                                         throw (uno::RuntimeException)
2606 {
2607     const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
2608 
2609     if ( nLineNoOfCaret >= 0 &&
2610          nLineNoOfCaret < GetPortionData().GetLineCount() )
2611     {
2612         return getTextAtLineNumber( nLineNoOfCaret );
2613     }
2614 
2615     return /*accessibility::*/TextSegment();
2616 }
2617 
2618 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
2619                                         throw (uno::RuntimeException)
2620 {
2621     const sal_Int32 nCaretPos = getCaretPosition();
2622     const sal_Int32 nLength = GetString().getLength();
2623     if ( !IsValidPosition( nCaretPos, nLength ) )
2624     {
2625         return -1;
2626     }
2627 
2628     sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
2629 
2630     // special handling for cursor positioned at end of text line via End key
2631     if ( nCaretPos != 0 )
2632     {
2633         i18n::Boundary aLineBound;
2634         GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2635         if ( nCaretPos == aLineBound.startPos )
2636         {
2637             SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
2638             if ( pCrsrShell != 0 )
2639             {
2640                 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
2641 
2642                 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect();
2643                 // translate core coordinates into accessibility coordinates
2644                 Window *pWin = GetWindow();
2645                 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2646 
2647                 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
2648 
2649                 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2650                 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
2651                 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
2652 
2653                 // convert into AWT Rectangle
2654                 const awt::Rectangle aCursorRect( aScreenRect.Left(),
2655                                                   aScreenRect.Top(),
2656                                                   aScreenRect.GetWidth(),
2657                                                   aScreenRect.GetHeight() );
2658 
2659                 if ( aCharRect.X != aCursorRect.X ||
2660                      aCharRect.Y != aCursorRect.Y )
2661                 {
2662                     --nLineNo;
2663                 }
2664             }
2665         }
2666     }
2667 
2668     return nLineNo;
2669 }
2670 
2671 // --> OD 2010-02-19 #i108125#
2672 void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2673 {
2674     mpParaChangeTrackInfo->reset();
2675 
2676     CheckRegistration( pOld, pNew );
2677 }
2678 // <--
2679