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