xref: /aoo41x/main/sw/source/core/access/accpara.cxx (revision 187afabe)
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         bRet = ((rBound.startPos <= nPos) && (nPos <= rBound.endPos));
762         DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" );
763         DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" );
764     }
765     else
766     {
767         // no break Iterator -> no glyph
768         rBound.startPos = nPos;
769         rBound.endPos = nPos;
770     }
771 
772     return bRet;
773 }
774 
775 
776 sal_Bool SwAccessibleParagraph::GetTextBoundary(
777     i18n::Boundary& rBound,
778     const ::rtl::OUString& rText,
779     sal_Int32 nPos,
780     sal_Int16 nTextType )
781     throw (
782         lang::IndexOutOfBoundsException,
783         lang::IllegalArgumentException,
784         uno::RuntimeException)
785 {
786     // error checking
787     if( !( AccessibleTextType::LINE == nTextType
788 				? IsValidPosition( nPos, rText.getLength() )
789 				: IsValidChar( nPos, rText.getLength() ) ) )
790         throw lang::IndexOutOfBoundsException();
791 
792     sal_Bool bRet;
793 
794     switch( nTextType )
795     {
796         case AccessibleTextType::WORD:
797             bRet = GetWordBoundary( rBound, rText, nPos );
798             break;
799 
800         case AccessibleTextType::SENTENCE:
801             bRet = GetSentenceBoundary( rBound, rText, nPos );
802             break;
803 
804         case AccessibleTextType::PARAGRAPH:
805             bRet = GetParagraphBoundary( rBound, rText, nPos );
806             break;
807 
808         case AccessibleTextType::CHARACTER:
809             bRet = GetCharBoundary( rBound, rText, nPos );
810             break;
811 
812         case AccessibleTextType::LINE:
813             bRet = GetLineBoundary( rBound, rText, nPos );
814             break;
815 
816         case AccessibleTextType::ATTRIBUTE_RUN:
817             bRet = GetAttributeBoundary( rBound, rText, nPos );
818             break;
819 
820         case AccessibleTextType::GLYPH:
821             bRet = GetGlyphBoundary( rBound, rText, nPos );
822             break;
823 
824         default:
825             throw lang::IllegalArgumentException( );
826     }
827 
828     return bRet;
829 }
830 
831 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void)
832         throw (uno::RuntimeException)
833 {
834 	vos::OGuard aGuard(Application::GetSolarMutex());
835 
836 	CHECK_FOR_DEFUNC( XAccessibleContext );
837 
838 	vos::OGuard aGuard2( aMutex );
839 	if( !sDesc.getLength() )
840 		sDesc = GetDescription();
841 
842     return sDesc;
843 }
844 
845 lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void)
846         throw (IllegalAccessibleComponentStateException, uno::RuntimeException)
847 {
848 	vos::OGuard aGuard(Application::GetSolarMutex());
849 
850 	SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() );
851 	if( !pTxtFrm )
852 	{
853 		THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" );
854 	}
855 
856 	const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode();
857     lang::Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) );
858 
859 	return aLoc;
860 }
861 
862 /** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
863 
864     OD 2005-12-02 #i27138#
865 
866     @author OD
867 */
868 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
869     throw ( uno::RuntimeException )
870 {
871     vos::OGuard aGuard(Application::GetSolarMutex());
872     CHECK_FOR_DEFUNC( XAccessibleContext );
873 
874     utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
875 
876     const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm());
877     ASSERT( pTxtFrm,
878             "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame");
879     if ( pTxtFrm )
880     {
881         const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) );
882         if ( pPrevCntFrm )
883         {
884             uno::Sequence< uno::Reference<XInterface> > aSequence(1);
885             aSequence[0] = GetMap()->GetContext( pPrevCntFrm );
886             AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
887                                         aSequence );
888             pHelper->AddRelation( aAccRel );
889         }
890 
891         const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) );
892         if ( pNextCntFrm )
893         {
894             uno::Sequence< uno::Reference<XInterface> > aSequence(1);
895             aSequence[0] = GetMap()->GetContext( pNextCntFrm );
896             AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
897                                         aSequence );
898             pHelper->AddRelation( aAccRel );
899         }
900     }
901 
902     return pHelper;
903 }
904 
905 void SAL_CALL SwAccessibleParagraph::grabFocus()
906         throw (uno::RuntimeException)
907 {
908 	vos::OGuard aGuard(Application::GetSolarMutex());
909 
910 	CHECK_FOR_DEFUNC( XAccessibleContext );
911 
912     // get cursor shell
913 	SwCrsrShell *pCrsrSh = GetCrsrShell();
914     // --> OD 2005-12-20 #i27301# - consider new method signature
915     SwPaM *pCrsr = GetCursor( false );
916     // <--
917 	const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
918 	const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode();
919 
920     if( pCrsrSh != 0 && pTxtNd != 0 &&
921 		( pCrsr == 0 ||
922 	 	  pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() ||
923 		  !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) )
924     {
925         // create pam for selection
926         SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ),
927 						pTxtFrm->GetOfst() );
928         SwPosition aStartPos( *pTxtNd, aIndex );
929         SwPaM aPaM( aStartPos );
930 
931         // set PaM at cursor shell
932 		Select( aPaM );
933 
934 
935     }
936 
937     /* ->#i13955# */
938     Window * pWindow = GetWindow();
939 
940     if (pWindow != NULL)
941         pWindow->GrabFocus();
942     /* <-#i13955# */
943 }
944 
945 // --> OD 2007-01-17 #i71385#
946 bool lcl_GetBackgroundColor( Color & rColor,
947                              const SwFrm* pFrm,
948                              SwCrsrShell* pCrsrSh )
949 {
950     const SvxBrushItem* pBackgrdBrush = 0;
951     const Color* pSectionTOXColor = 0;
952     SwRect aDummyRect;
953     if ( pFrm &&
954          pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) )
955     {
956         if ( pSectionTOXColor )
957         {
958             rColor = *pSectionTOXColor;
959             return true;
960         }
961         else
962         {
963             rColor =  pBackgrdBrush->GetColor();
964             return true;
965         }
966     }
967     else if ( pCrsrSh )
968     {
969         rColor = pCrsrSh->Imp()->GetRetoucheColor();
970         return true;
971     }
972 
973     return false;
974 }
975 
976 sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground()
977                                 throw (uno::RuntimeException)
978 {
979     Color aBackgroundCol;
980 
981     if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
982     {
983         if ( aBackgroundCol.IsDark() )
984         {
985             return COL_WHITE;
986         }
987         else
988         {
989             return COL_BLACK;
990         }
991     }
992 
993     return SwAccessibleContext::getForeground();
994 }
995 
996 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
997                                 throw (uno::RuntimeException)
998 {
999     Color aBackgroundCol;
1000 
1001     if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
1002     {
1003         return aBackgroundCol.GetColor();
1004     }
1005 
1006     return SwAccessibleContext::getBackground();
1007 }
1008 // <--
1009 
1010 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getImplementationName()
1011         throw( uno::RuntimeException )
1012 {
1013     return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
1014 }
1015 
1016 sal_Bool SAL_CALL SwAccessibleParagraph::supportsService(
1017 		const ::rtl::OUString& sTestServiceName)
1018     throw (uno::RuntimeException)
1019 {
1020 	return sTestServiceName.equalsAsciiL( sServiceName,
1021 										  sizeof(sServiceName)-1 ) ||
1022 		   sTestServiceName.equalsAsciiL( sAccessibleServiceName,
1023 				   						  sizeof(sAccessibleServiceName)-1 );
1024 }
1025 
1026 uno::Sequence< ::rtl::OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames()
1027         throw( uno::RuntimeException )
1028 {
1029     uno::Sequence< ::rtl::OUString > aRet(2);
1030     ::rtl::OUString* pArray = aRet.getArray();
1031     pArray[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
1032     pArray[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
1033 	return aRet;
1034 }
1035 
1036 //
1037 //=====  XInterface  =======================================================
1038 //
1039 
1040 uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType )
1041     throw (uno::RuntimeException)
1042 {
1043     uno::Any aRet;
1044     if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) )
1045     {
1046         uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity
1047         aRet <<= aAccText;
1048     }
1049     else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) )
1050     {
1051         uno::Reference<XAccessibleEditableText> aAccEditText = this;
1052         aRet <<= aAccEditText;
1053     }
1054     else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) )
1055     {
1056         uno::Reference<XAccessibleSelection> aAccSel = this;
1057         aRet <<= aAccSel;
1058     }
1059     else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) )
1060     {
1061         uno::Reference<XAccessibleHypertext> aAccHyp = this;
1062         aRet <<= aAccHyp;
1063     }
1064     // --> OD 2006-07-13 #i63870#
1065     // add interface com::sun:star:accessibility::XAccessibleTextAttributes
1066     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) )
1067     {
1068         uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
1069         aRet <<= aAccTextAttr;
1070     }
1071     // <--
1072     // --> OD 2008-06-10 #i89175#
1073     // add interface com::sun:star:accessibility::XAccessibleTextMarkup
1074     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) )
1075     {
1076         uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this;
1077         aRet <<= aAccTextMarkup;
1078     }
1079     // add interface com::sun:star:accessibility::XAccessibleMultiLineText
1080     else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) )
1081     {
1082         uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this;
1083         aRet <<= aAccMultiLineText;
1084     }
1085     // <--
1086     else
1087     {
1088         aRet = SwAccessibleContext::queryInterface(rType);
1089     }
1090 
1091     return aRet;
1092 }
1093 
1094 //====== XTypeProvider ====================================================
1095 uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException)
1096 {
1097     uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
1098 
1099 	sal_Int32 nIndex = aTypes.getLength();
1100     // --> OD 2006-07-13 #i63870#
1101     // add type accessibility::XAccessibleTextAttributes
1102     // --> OD 2008-06-10 #i89175#
1103     // add type accessibility::XAccessibleTextMarkup and accessibility::XAccessibleMultiLineText
1104     aTypes.realloc( nIndex + 6 );
1105 
1106     uno::Type* pTypes = aTypes.getArray();
1107 	pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) );
1108     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) );
1109 	pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) );
1110     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) );
1111     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) );
1112 	pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) );
1113     // <--
1114 
1115 	return aTypes;
1116 }
1117 
1118 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId()
1119         throw(uno::RuntimeException)
1120 {
1121     vos::OGuard aGuard(Application::GetSolarMutex());
1122     static uno::Sequence< sal_Int8 > aId( 16 );
1123     static sal_Bool bInit = sal_False;
1124     if(!bInit)
1125     {
1126         rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
1127         bInit = sal_True;
1128     }
1129     return aId;
1130 }
1131 
1132 
1133 //
1134 //=====  XAccesibleText  ===================================================
1135 //
1136 
1137 sal_Int32 SwAccessibleParagraph::getCaretPosition()
1138     throw (uno::RuntimeException)
1139 {
1140 	vos::OGuard aGuard(Application::GetSolarMutex());
1141 
1142 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1143 
1144     sal_Int32 nRet = GetCaretPos();
1145 	{
1146         vos::OGuard aOldCaretPosGuard( aMutex );
1147 		ASSERT( nRet == nOldCaretPos, "caret pos out of sync" );
1148 		nOldCaretPos = nRet;
1149 	}
1150 	if( -1 != nRet )
1151 	{
1152 		::vos::ORef < SwAccessibleContext > xThis( this );
1153 		GetMap()->SetCursorContext( xThis );
1154 	}
1155 
1156     return nRet;
1157 }
1158 
1159 sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
1160     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1161 {
1162 	vos::OGuard aGuard(Application::GetSolarMutex());
1163 
1164 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1165 
1166     // parameter checking
1167     sal_Int32 nLength = GetString().getLength();
1168     if ( ! IsValidPosition( nIndex, nLength ) )
1169     {
1170         throw lang::IndexOutOfBoundsException();
1171     }
1172 
1173     sal_Bool bRet = sal_False;
1174 
1175     // get cursor shell
1176     SwCrsrShell* pCrsrShell = GetCrsrShell();
1177     if( pCrsrShell != NULL )
1178     {
1179         // create pam for selection
1180         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1181         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex));
1182         SwPosition aStartPos( *pNode, aIndex );
1183         SwPaM aPaM( aStartPos );
1184 
1185         // set PaM at cursor shell
1186         bRet = Select( aPaM );
1187     }
1188 
1189     return bRet;
1190 }
1191 
1192 sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex )
1193     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1194 {
1195 	vos::OGuard aGuard(Application::GetSolarMutex());
1196 
1197 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1198 
1199     ::rtl::OUString sText( GetString() );
1200 
1201     // return character (if valid)
1202     if( IsValidChar(nIndex, sText.getLength() ) )
1203     {
1204         return sText.getStr()[nIndex];
1205     }
1206     else
1207         throw lang::IndexOutOfBoundsException();
1208 }
1209 
1210 // --> OD 2006-07-20 #i63870#
1211 // re-implement method on behalf of methods <_getDefaultAttributesImpl(..)> and
1212 // <_getRunAttributesImpl(..)>
1213 uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes(
1214     sal_Int32 nIndex,
1215     const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1216     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1217 {
1218 
1219 	vos::OGuard aGuard(Application::GetSolarMutex());
1220 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1221 
1222     const ::rtl::OUString& rText = GetString();
1223 
1224     if( ! IsValidChar( nIndex, rText.getLength() ) )
1225         throw lang::IndexOutOfBoundsException();
1226 
1227     // retrieve default character attributes
1228     tAccParaPropValMap aDefAttrSeq;
1229     _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true );
1230 
1231     // retrieved run character attributes
1232     tAccParaPropValMap aRunAttrSeq;
1233     _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1234 
1235     // merge default and run attributes
1236     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1237     PropertyValue* pValues = aValues.getArray();
1238     sal_Int32 i = 0;
1239     for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin();
1240           aDefIter != aDefAttrSeq.end();
1241           ++aDefIter )
1242     {
1243         tAccParaPropValMap::const_iterator aRunIter =
1244                                         aRunAttrSeq.find( aDefIter->first );
1245         if ( aRunIter != aRunAttrSeq.end() )
1246         {
1247             pValues[i] = aRunIter->second;
1248         }
1249         else
1250         {
1251             pValues[i] = aDefIter->second;
1252         }
1253         ++i;
1254     }
1255 
1256 //    // create a (dummy) text portion for the sole purpose of calling
1257 //    // getPropertyValues on it
1258 //    Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 );
1259 
1260 //    // get values
1261 //    Sequence<OUString> aNames = getAttributeNames();
1262 //    sal_Int32 nLength = aNames.getLength();
1263 //    Sequence<Any> aAnys( nLength );
1264 //    aAnys = xPortion->getPropertyValues( aNames );
1265 
1266 //    // copy names + anys into return sequence
1267 //    Sequence<PropertyValue> aValues( aNames.getLength() );
1268 //    const OUString* pNames = aNames.getConstArray();
1269 //    const Any* pAnys = aAnys.getConstArray();
1270 //    PropertyValue* pValues = aValues.getArray();
1271 //    for( sal_Int32 i = 0; i < nLength; i++ )
1272 //    {
1273 //        PropertyValue& rValue = pValues[i];
1274 //        rValue.Name = pNames[i];
1275 //        rValue.Value = pAnys[i];
1276 //        rValue.Handle = -1;                         // handle not supported
1277 //        rValue.State = PropertyState_DIRECT_VALUE;  // states not supported
1278 //    }
1279 
1280 //    // adjust background color if we're in a gray portion
1281 //    DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name.
1282 //                equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")),
1283 //                "Please adjust CHAR_BACK_COLOR_POS constant." );
1284 //    if( GetPortionData().IsInGrayPortion( nIndex ) )
1285 //        pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
1286 
1287     return aValues;
1288 }
1289 
1290 // --> OD 2006-07-11 #i63870#
1291 void SwAccessibleParagraph::_getDefaultAttributesImpl(
1292         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1293         tAccParaPropValMap& rDefAttrSeq,
1294         const bool bOnlyCharAttrs )
1295 {
1296     // retrieve default attributes
1297     const SwTxtNode* pTxtNode( GetTxtNode() );
1298     ::boost::scoped_ptr<SfxItemSet> pSet;
1299     if ( !bOnlyCharAttrs )
1300     {
1301         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1302                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1303                                RES_PARATR_BEGIN, RES_PARATR_END - 1,
1304                                RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1305                                0 ) );
1306     }
1307     else
1308     {
1309         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1310                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1311                                0 ) );
1312     }
1313     // --> OD 2007-11-12 #i82637#
1314     // From the perspective of the a11y API the default character attributes
1315     // are the character attributes, which are set at the paragraph style
1316     // of the paragraph. The character attributes set at the automatic paragraph
1317     // style of the paragraph are treated as run attributes.
1318 //    pTxtNode->SwCntntNode::GetAttr( *pSet );
1319     // get default paragraph attributes, if needed, and merge these into <pSet>
1320     if ( !bOnlyCharAttrs )
1321     {
1322         SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1323                              RES_PARATR_BEGIN, RES_PARATR_END - 1,
1324                              RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1325                              0 );
1326         pTxtNode->SwCntntNode::GetAttr( aParaSet );
1327         pSet->Put( aParaSet );
1328     }
1329     // get default character attributes and merge these into <pSet>
1330     ASSERT( pTxtNode->GetTxtColl(),
1331             "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" );
1332     if ( pTxtNode->GetTxtColl() )
1333     {
1334         SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1335                              RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1336                              0 );
1337         aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() );
1338         pSet->Put( aCharSet );
1339     }
1340     // <--
1341 
1342     // build-up sequence containing the run attributes <rDefAttrSeq>
1343     tAccParaPropValMap aDefAttrSeq;
1344     {
1345         const SfxItemPropertyMap* pPropMap =
1346                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1347         PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
1348         PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1349         while ( aPropIt != aPropertyEntries.end() )
1350         {
1351             const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID );
1352             if ( pItem )
1353             {
1354                 uno::Any aVal;
1355                 pItem->QueryValue( aVal, aPropIt->nMemberId );
1356 
1357                 PropertyValue rPropVal;
1358                 rPropVal.Name = aPropIt->sName;
1359                 rPropVal.Value = aVal;
1360                 rPropVal.Handle = -1;
1361                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1362 
1363                 aDefAttrSeq[rPropVal.Name] = rPropVal;
1364             }
1365             ++aPropIt;
1366         }
1367 
1368         // --> OD 2007-01-15 #i72800#
1369         // add property value entry for the paragraph style
1370         if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() )
1371         {
1372             const ::rtl::OUString sParaStyleName =
1373                     ::rtl::OUString::createFromAscii(
1374                             GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName );
1375             if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() )
1376             {
1377                 PropertyValue rPropVal;
1378                 rPropVal.Name = sParaStyleName;
1379                 uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) );
1380                 rPropVal.Value = aVal;
1381                 rPropVal.Handle = -1;
1382                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1383 
1384                 aDefAttrSeq[rPropVal.Name] = rPropVal;
1385             }
1386         }
1387         // <--
1388 
1389         // --> OD 2007-01-15 #i73371#
1390         // resolve value text::WritingMode2::PAGE of property value entry WritingMode
1391         if ( !bOnlyCharAttrs && GetFrm() )
1392         {
1393             const ::rtl::OUString sWritingMode =
1394                     ::rtl::OUString::createFromAscii(
1395                             GetPropName( UNO_NAME_WRITING_MODE ).pName );
1396             tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode );
1397             if ( aIter != aDefAttrSeq.end() )
1398             {
1399                 PropertyValue rPropVal( aIter->second );
1400                 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
1401                 if ( nVal == text::WritingMode2::PAGE )
1402                 {
1403                     const SwFrm* pUpperFrm( GetFrm()->GetUpper() );
1404                     while ( pUpperFrm )
1405                     {
1406                         if ( pUpperFrm->GetType() &
1407                                ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) )
1408                         {
1409                             if ( pUpperFrm->IsVertical() )
1410                             {
1411                                 nVal = text::WritingMode2::TB_RL;
1412                             }
1413                             else if ( pUpperFrm->IsRightToLeft() )
1414                             {
1415                                 nVal = text::WritingMode2::RL_TB;
1416                             }
1417                             else
1418                             {
1419                                 nVal = text::WritingMode2::LR_TB;
1420                             }
1421                             rPropVal.Value <<= nVal;
1422                             aDefAttrSeq[rPropVal.Name] = rPropVal;
1423                             break;
1424                         }
1425 
1426                         if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) )
1427                         {
1428                             pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm();
1429                         }
1430                         else
1431                         {
1432                             pUpperFrm = pUpperFrm->GetUpper();
1433                         }
1434                     }
1435                 }
1436             }
1437         }
1438         // <--
1439     }
1440 
1441     if ( aRequestedAttributes.getLength() == 0 )
1442     {
1443         rDefAttrSeq = aDefAttrSeq;
1444     }
1445     else
1446     {
1447         const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1448         const sal_Int32 nLength = aRequestedAttributes.getLength();
1449         for( sal_Int32 i = 0; i < nLength; ++i )
1450         {
1451             tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] );
1452             if ( aIter != aDefAttrSeq.end() )
1453             {
1454                 rDefAttrSeq[ aIter->first ] = aIter->second;
1455             }
1456         }
1457     }
1458 }
1459 
1460 uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
1461         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1462         throw ( uno::RuntimeException )
1463 {
1464     vos::OGuard aGuard(Application::GetSolarMutex());
1465     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1466 
1467     tAccParaPropValMap aDefAttrSeq;
1468     _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
1469 
1470     // --> OD 2010-03-08 #i92233#
1471     static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "MMToPixelRatio" ) );
1472     bool bProvideMMToPixelRatio( false );
1473     {
1474         if ( aRequestedAttributes.getLength() == 0 )
1475         {
1476             bProvideMMToPixelRatio = true;
1477         }
1478         else
1479         {
1480             const rtl::OUString* aRequestedAttrIter =
1481                   ::std::find( ::comphelper::stl_begin( aRequestedAttributes ),
1482                                ::comphelper::stl_end( aRequestedAttributes ),
1483                                sMMToPixelRatio );
1484             if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) )
1485             {
1486                 bProvideMMToPixelRatio = true;
1487             }
1488         }
1489     }
1490     // <--
1491 
1492     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() +
1493                                             ( bProvideMMToPixelRatio ? 1 : 0 ) );
1494     PropertyValue* pValues = aValues.getArray();
1495     sal_Int32 i = 0;
1496     for ( tAccParaPropValMap::const_iterator aIter  = aDefAttrSeq.begin();
1497           aIter != aDefAttrSeq.end();
1498           ++aIter )
1499     {
1500         pValues[i] = aIter->second;
1501         ++i;
1502     }
1503 
1504     // --> OD 2010-03-08 #i92233#
1505     if ( bProvideMMToPixelRatio )
1506     {
1507         PropertyValue rPropVal;
1508         rPropVal.Name = sMMToPixelRatio;
1509         const Size a100thMMSize( 1000, 1000 );
1510         const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize );
1511         const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width();
1512         rPropVal.Value = uno::makeAny( fRatio );
1513         rPropVal.Handle = -1;
1514         rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1515         pValues[ aValues.getLength() - 1 ] = rPropVal;
1516     }
1517     // <--
1518 
1519     return aValues;
1520 }
1521 
1522 void SwAccessibleParagraph::_getRunAttributesImpl(
1523         const sal_Int32 nIndex,
1524         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1525         tAccParaPropValMap& rRunAttrSeq )
1526 {
1527     // create PaM for character at position <nIndex>
1528     SwPaM* pPaM( 0 );
1529     {
1530         const SwTxtNode* pTxtNode( GetTxtNode() );
1531         SwPosition* pStartPos = new SwPosition( *pTxtNode );
1532         pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) );
1533         SwPosition* pEndPos = new SwPosition( *pTxtNode );
1534         pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) );
1535 
1536         pPaM = new SwPaM( *pStartPos, *pEndPos );
1537 
1538         delete pStartPos;
1539         delete pEndPos;
1540     }
1541 
1542     // retrieve character attributes for the created PaM <pPaM>
1543     SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(),
1544                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1545                      0 );
1546     // --> OD 2007-11-12 #i82637#
1547     // From the perspective of the a11y API the character attributes, which
1548     // are set at the automatic paragraph style of the paragraph are treated
1549     // as run attributes.
1550 //    SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True );
1551     // get character attributes from automatic paragraph style and merge these into <aSet>
1552     {
1553         const SwTxtNode* pTxtNode( GetTxtNode() );
1554         if ( pTxtNode->HasSwAttrSet() )
1555         {
1556             SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(),
1557                                                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1558                                                      0 );
1559             aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False );
1560             aSet.Put( aAutomaticParaStyleCharAttrs );
1561         }
1562     }
1563     // get character attributes at <pPaM> and merge these into <aSet>
1564     {
1565         SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(),
1566                                     RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1567                                     0 );
1568         SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True);
1569         aSet.Put( aCharAttrsAtPaM );
1570     }
1571     // <--
1572 
1573     // build-up sequence containing the run attributes <rRunAttrSeq>
1574     {
1575         tAccParaPropValMap aRunAttrSeq;
1576         {
1577             // --> OD 2007-11-12 #i82637#
1578             tAccParaPropValMap aDefAttrSeq;
1579             uno::Sequence< ::rtl::OUString > aDummy;
1580             _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true );
1581             // <--
1582 
1583             const SfxItemPropertyMap* pPropMap =
1584                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1585             PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
1586             PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1587             while ( aPropIt != aPropertyEntries.end() )
1588             {
1589                 const SfxPoolItem* pItem( 0 );
1590                 // --> OD 2007-11-12 #i82637#
1591                 // Found character attributes, whose value equals the value of
1592                 // the corresponding default character attributes, are excluded.
1593                 if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET )
1594                 {
1595                     uno::Any aVal;
1596                     pItem->QueryValue( aVal, aPropIt->nMemberId );
1597 
1598                     PropertyValue rPropVal;
1599                     rPropVal.Name = aPropIt->sName;
1600                     rPropVal.Value = aVal;
1601                     rPropVal.Handle = -1;
1602                     rPropVal.State = PropertyState_DIRECT_VALUE;
1603 
1604                     tAccParaPropValMap::const_iterator aDefIter =
1605                                             aDefAttrSeq.find( rPropVal.Name );
1606                     if ( aDefIter == aDefAttrSeq.end() ||
1607                          rPropVal.Value != aDefIter->second.Value )
1608                     {
1609                         aRunAttrSeq[rPropVal.Name] = rPropVal;
1610                     }
1611                 }
1612 
1613                 ++aPropIt;
1614             }
1615         }
1616 
1617         if ( aRequestedAttributes.getLength() == 0 )
1618         {
1619             rRunAttrSeq = aRunAttrSeq;
1620         }
1621         else
1622         {
1623             const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1624             const sal_Int32 nLength = aRequestedAttributes.getLength();
1625             for( sal_Int32 i = 0; i < nLength; ++i )
1626             {
1627                 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1628                 if ( aIter != aRunAttrSeq.end() )
1629                 {
1630                     rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1631                 }
1632             }
1633         }
1634     }
1635 
1636     delete pPaM;
1637 }
1638 
1639 uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
1640         sal_Int32 nIndex,
1641         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1642         throw ( lang::IndexOutOfBoundsException,
1643                 uno::RuntimeException )
1644 {
1645     vos::OGuard aGuard(Application::GetSolarMutex());
1646     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1647 
1648     {
1649         const ::rtl::OUString& rText = GetString();
1650         if ( !IsValidChar( nIndex, rText.getLength() ) )
1651         {
1652             throw lang::IndexOutOfBoundsException();
1653         }
1654     }
1655 
1656     tAccParaPropValMap aRunAttrSeq;
1657     _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1658 
1659     uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() );
1660     PropertyValue* pValues = aValues.getArray();
1661     sal_Int32 i = 0;
1662     for ( tAccParaPropValMap::const_iterator aIter  = aRunAttrSeq.begin();
1663           aIter != aRunAttrSeq.end();
1664           ++aIter )
1665     {
1666         pValues[i] = aIter->second;
1667         ++i;
1668     }
1669 
1670     return aValues;
1671 }
1672 // <--
1673 
1674 awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
1675     sal_Int32 nIndex )
1676     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1677 {
1678 	vos::OGuard aGuard(Application::GetSolarMutex());
1679 
1680 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1681 
1682 
1683     /*  #i12332# The position after the string needs special treatment.
1684         IsValidChar -> IsValidPosition
1685     */
1686     if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
1687         throw lang::IndexOutOfBoundsException();
1688 
1689     /*  #i12332#  */
1690     sal_Bool bBehindText = sal_False;
1691     if ( nIndex == GetString().getLength() )
1692         bBehindText = sal_True;
1693 
1694     // get model position & prepare GetCharRect() arguments
1695     SwCrsrMoveState aMoveState;
1696     aMoveState.bRealHeight = sal_True;
1697     aMoveState.bRealWidth = sal_True;
1698     SwSpecialPos aSpecialPos;
1699     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1700 
1701     sal_uInt16 nPos = 0;
1702 
1703     /*  #i12332# FillSpecialPos does not accept nIndex ==
1704          GetString().getLength(). In that case nPos is set to the
1705          length of the string in the core. This way GetCharRect
1706          returns the rectangle for a cursor at the end of the
1707          paragraph. */
1708     if (bBehindText)
1709     {
1710         nPos = pNode->GetTxt().Len();
1711     }
1712     else
1713         nPos = GetPortionData().FillSpecialPos
1714             (nIndex, aSpecialPos, aMoveState.pSpecialPos );
1715 
1716     // call GetCharRect
1717     SwRect aCoreRect;
1718     SwIndex aIndex( pNode, nPos );
1719     SwPosition aPosition( *pNode, aIndex );
1720     GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
1721 
1722     // translate core coordinates into accessibility coordinates
1723 	Window *pWin = GetWindow();
1724 	CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1725 
1726 	Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
1727     SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
1728 
1729 	Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
1730 	aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
1731 
1732     // convert into AWT Rectangle
1733     return awt::Rectangle(
1734         aScreenRect.Left(), aScreenRect.Top(),
1735         aScreenRect.GetWidth(), aScreenRect.GetHeight() );
1736 }
1737 
1738 sal_Int32 SwAccessibleParagraph::getCharacterCount()
1739     throw (uno::RuntimeException)
1740 {
1741 	vos::OGuard aGuard(Application::GetSolarMutex());
1742 
1743 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1744 
1745     return GetString().getLength();
1746 }
1747 
1748 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
1749     throw (uno::RuntimeException)
1750 {
1751 	vos::OGuard aGuard(Application::GetSolarMutex());
1752 
1753 
1754 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1755 
1756     // construct SwPosition (where GetCrsrOfst() will put the result into)
1757     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1758     SwIndex aIndex( pNode, 0);
1759     SwPosition aPos( *pNode, aIndex );
1760 
1761     // construct Point (translate into layout coordinates)
1762 	Window *pWin = GetWindow();
1763 	CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1764     Point aPoint( rPoint.X, rPoint.Y );
1765     SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root
1766 	Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
1767 	aPoint.X() += aPixPos.X();
1768 	aPoint.Y() += aPixPos.Y();
1769     MapMode aMapMode = pWin->GetMapMode();
1770 	Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
1771 	if( !aLogBounds.IsInside( aCorePoint ) )
1772     {
1773         /* #i12332# rPoint is may also be in rectangle returned by
1774             getCharacterBounds(getCharacterCount() */
1775 
1776         awt::Rectangle aRectEndPos =
1777             getCharacterBounds(getCharacterCount());
1778 
1779         if (rPoint.X - aRectEndPos.X >= 0 &&
1780             rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
1781             rPoint.Y - aRectEndPos.Y >= 0 &&
1782             rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
1783             return getCharacterCount();
1784 
1785 		return -1;
1786     }
1787 
1788     // ask core for position
1789     DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
1790     DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
1791     const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
1792     SwCrsrMoveState aMoveState;
1793     aMoveState.bPosMatchesBounds = sal_True;
1794     sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState );
1795 
1796     SwIndex aCntntIdx = aPos.nContent;
1797     const xub_StrLen nIndex = aCntntIdx.GetIndex();
1798     if ( nIndex > 0 )
1799     {
1800         SwRect aResultRect;
1801         pFrm->GetCharRect( aResultRect, aPos );
1802         bool bVert = pFrm->IsVertical();
1803         bool bR2L = pFrm->IsRightToLeft();
1804 
1805         if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) ||
1806              ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) ||
1807              ( bR2L  && aResultRect.Right()   < aCorePoint.X()) )
1808         {
1809             SwIndex aIdxPrev( pNode, nIndex - 1);
1810             SwPosition aPosPrev( *pNode, aIdxPrev );
1811             SwRect aResultRectPrev;
1812             pFrm->GetCharRect( aResultRectPrev, aPosPrev );
1813             if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ||
1814                  ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) ||
1815                  (  bR2L && aResultRectPrev.Right()   > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) )
1816                 aPos = aPosPrev;
1817         }
1818     }
1819 
1820     return bSuccess ?
1821         GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() )
1822         : -1L;
1823 }
1824 
1825 ::rtl::OUString SwAccessibleParagraph::getSelectedText()
1826     throw (uno::RuntimeException)
1827 {
1828     vos::OGuard aGuard(Application::GetSolarMutex());
1829 
1830 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1831 
1832     sal_Int32 nStart, nEnd;
1833     sal_Bool bSelected = GetSelection( nStart, nEnd );
1834     return bSelected
1835            ? GetString().copy( nStart, nEnd - nStart )
1836            : ::rtl::OUString();
1837 }
1838 
1839 sal_Int32 SwAccessibleParagraph::getSelectionStart()
1840     throw (uno::RuntimeException)
1841 {
1842 	vos::OGuard aGuard(Application::GetSolarMutex());
1843 
1844 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1845 
1846     sal_Int32 nStart, nEnd;
1847     GetSelection( nStart, nEnd );
1848     return nStart;
1849 }
1850 
1851 sal_Int32 SwAccessibleParagraph::getSelectionEnd()
1852     throw (uno::RuntimeException)
1853 {
1854 	vos::OGuard aGuard(Application::GetSolarMutex());
1855 
1856 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1857 
1858     sal_Int32 nStart, nEnd;
1859     GetSelection( nStart, nEnd );
1860     return nEnd;
1861 }
1862 
1863 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1864     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1865 {
1866 	vos::OGuard aGuard(Application::GetSolarMutex());
1867 
1868 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1869 
1870     // parameter checking
1871     sal_Int32 nLength = GetString().getLength();
1872     if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
1873     {
1874         throw lang::IndexOutOfBoundsException();
1875     }
1876 
1877     sal_Bool bRet = sal_False;
1878 
1879     // get cursor shell
1880     SwCrsrShell* pCrsrShell = GetCrsrShell();
1881     if( pCrsrShell != NULL )
1882     {
1883         // create pam for selection
1884         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1885         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex));
1886         SwPosition aStartPos( *pNode, aIndex );
1887         SwPaM aPaM( aStartPos );
1888         aPaM.SetMark();
1889         aPaM.GetPoint()->nContent =
1890             GetPortionData().GetModelPosition(nEndIndex);
1891 
1892         // set PaM at cursor shell
1893         bRet = Select( aPaM );
1894     }
1895 
1896     return bRet;
1897 }
1898 
1899 ::rtl::OUString SwAccessibleParagraph::getText()
1900     throw (uno::RuntimeException)
1901 {
1902 	vos::OGuard aGuard(Application::GetSolarMutex());
1903 
1904 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1905 
1906     return GetString();
1907 }
1908 
1909 ::rtl::OUString SwAccessibleParagraph::getTextRange(
1910     sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1911     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1912 {
1913 	vos::OGuard aGuard(Application::GetSolarMutex());
1914 
1915 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1916 
1917     ::rtl::OUString sText( GetString() );
1918 
1919     if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
1920     {
1921         OrderRange( nStartIndex, nEndIndex );
1922         return sText.copy(nStartIndex, nEndIndex-nStartIndex );
1923     }
1924     else
1925         throw lang::IndexOutOfBoundsException();
1926 }
1927 
1928 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1929 {
1930 	vos::OGuard aGuard(Application::GetSolarMutex());
1931 
1932 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1933 
1934     /*accessibility::*/TextSegment aResult;
1935     aResult.SegmentStart = -1;
1936     aResult.SegmentEnd = -1;
1937 
1938     const ::rtl::OUString rText = GetString();
1939     // implement the silly specification that first position after
1940     // text must return an empty string, rather than throwing an
1941     // IndexOutOfBoundsException, except for LINE, where the last
1942 	// line is returned
1943     if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
1944 		return aResult;
1945 
1946     // with error checking
1947     i18n::Boundary aBound;
1948     sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1949 
1950     DBG_ASSERT( aBound.startPos >= 0,               "illegal boundary" );
1951     DBG_ASSERT( aBound.startPos <= aBound.endPos,   "illegal boundary" );
1952 
1953     // return word (if present)
1954     if ( bWord )
1955     {
1956     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1957     	aResult.SegmentStart = aBound.startPos;
1958     	aResult.SegmentEnd = aBound.endPos;
1959     }
1960 
1961     return aResult;
1962 }
1963 
1964 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1965 {
1966 	vos::OGuard aGuard(Application::GetSolarMutex());
1967 
1968 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1969 
1970     const ::rtl::OUString rText = GetString();
1971 
1972     /*accessibility::*/TextSegment aResult;
1973     aResult.SegmentStart = -1;
1974     aResult.SegmentEnd = -1;
1975 
1976     // get starting pos
1977     i18n::Boundary aBound;
1978     if (nIndex ==  rText.getLength())
1979         aBound.startPos = aBound.endPos = nIndex;
1980     else
1981     {
1982         sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
1983 
1984         if ( ! bTmp )
1985             aBound.startPos = aBound.endPos = nIndex;
1986     }
1987 
1988     // now skip to previous word
1989     sal_Bool bWord = sal_False;
1990     while( !bWord )
1991     {
1992         nIndex = min( nIndex, aBound.startPos ) - 1;
1993         if( nIndex >= 0 )
1994             bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1995         else
1996             break;  // exit if beginning of string is reached
1997     }
1998 
1999     if ( bWord )
2000     {
2001     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2002     	aResult.SegmentStart = aBound.startPos;
2003     	aResult.SegmentEnd = aBound.endPos;
2004     };
2005     return aResult;
2006 }
2007 
2008 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
2009 {
2010 	vos::OGuard aGuard(Application::GetSolarMutex());
2011 
2012 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2013 
2014     /*accessibility::*/TextSegment aResult;
2015     aResult.SegmentStart = -1;
2016     aResult.SegmentEnd = -1;
2017     const ::rtl::OUString rText = GetString();
2018 
2019     // implement the silly specification that first position after
2020     // text must return an empty string, rather than throwing an
2021     // IndexOutOfBoundsException
2022     if( nIndex == rText.getLength() )
2023         return aResult;
2024 
2025 
2026     // get first word, then skip to next word
2027     i18n::Boundary aBound;
2028     GetTextBoundary( aBound, rText, nIndex, nTextType );
2029     sal_Bool bWord = sal_False;
2030     while( !bWord )
2031     {
2032         nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
2033         if( nIndex < rText.getLength() )
2034             bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2035         else
2036             break;  // exit if end of string is reached
2037     }
2038 
2039     if ( bWord )
2040     {
2041     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2042     	aResult.SegmentStart = aBound.startPos;
2043     	aResult.SegmentEnd = aBound.endPos;
2044     }
2045     return aResult;
2046 }
2047 
2048 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2049     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2050 {
2051 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2052 	vos::OGuard aGuard(Application::GetSolarMutex());
2053 
2054     // select and copy (through dispatch mechanism)
2055     setSelection( nStartIndex, nEndIndex );
2056     ExecuteAtViewShell( SID_COPY );
2057     return sal_True;
2058 }
2059 
2060 
2061 //
2062 //=====  XAccesibleEditableText  ==========================================
2063 //
2064 
2065 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2066     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2067 {
2068 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2069 	vos::OGuard aGuard(Application::GetSolarMutex());
2070 
2071 	if( !IsEditableState() )
2072 		return sal_False;
2073 
2074     // select and cut (through dispatch mechanism)
2075     setSelection( nStartIndex, nEndIndex );
2076     ExecuteAtViewShell( SID_CUT );
2077     return sal_True;
2078 }
2079 
2080 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
2081     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2082 {
2083 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2084 	vos::OGuard aGuard(Application::GetSolarMutex());
2085 
2086 	if( !IsEditableState() )
2087 		return sal_False;
2088 
2089     // select and paste (through dispatch mechanism)
2090     setSelection( nIndex, nIndex );
2091     ExecuteAtViewShell( SID_PASTE );
2092     return sal_True;
2093 }
2094 
2095 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2096     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2097 {
2098     return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() );
2099 }
2100 
2101 sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex )
2102     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2103 {
2104     return replaceText( nIndex, nIndex, sText );
2105 }
2106 
2107 sal_Bool SwAccessibleParagraph::replaceText(
2108     sal_Int32 nStartIndex, sal_Int32 nEndIndex,
2109     const ::rtl::OUString& sReplacement )
2110     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2111 {
2112 	vos::OGuard aGuard(Application::GetSolarMutex());
2113 
2114 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2115 
2116     const ::rtl::OUString& rText = GetString();
2117 
2118     if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2119     {
2120 		if( !IsEditableState() )
2121 			return sal_False;
2122 
2123         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2124 
2125         // translate positions
2126         sal_uInt16 nStart, nEnd;
2127         sal_Bool bSuccess = GetPortionData().GetEditableRange(
2128                                         nStartIndex, nEndIndex, nStart, nEnd );
2129 
2130         // edit only if the range is editable
2131         if( bSuccess )
2132         {
2133             // create SwPosition for nStartIndex
2134             SwIndex aIndex( pNode, nStart );
2135             SwPosition aStartPos( *pNode, aIndex );
2136 
2137             // create SwPosition for nEndIndex
2138             SwPosition aEndPos( aStartPos );
2139             aEndPos.nContent = nEnd;
2140 
2141             // now create XTextRange as helper and set string
2142             const uno::Reference<text::XTextRange> xRange(
2143                 SwXTextRange::CreateXTextRange(
2144                     *pNode->GetDoc(), aStartPos, &aEndPos));
2145             xRange->setString(sReplacement);
2146 
2147             // delete portion data
2148             ClearPortionData();
2149         }
2150 
2151         return bSuccess;
2152     }
2153     else
2154         throw lang::IndexOutOfBoundsException();
2155 }
2156 
2157 struct IndexCompare
2158 {
2159     const PropertyValue* pValues;
2160     IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
2161     bool operator() ( const sal_Int32& a, const sal_Int32& b ) const
2162     {
2163         return (pValues[a].Name < pValues[b].Name) ? true : false;
2164     }
2165 };
2166 
2167 
2168 sal_Bool SwAccessibleParagraph::setAttributes(
2169     sal_Int32 nStartIndex,
2170     sal_Int32 nEndIndex,
2171     const uno::Sequence<PropertyValue>& rAttributeSet )
2172     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2173 {
2174 	vos::OGuard aGuard(Application::GetSolarMutex());
2175 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
2176 
2177     const ::rtl::OUString& rText = GetString();
2178 
2179     if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2180         throw lang::IndexOutOfBoundsException();
2181 
2182 	if( !IsEditableState() )
2183 		return sal_False;
2184 
2185 
2186     // create a (dummy) text portion for the sole purpose of calling
2187     // setPropertyValue on it
2188     uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
2189                                                               nEndIndex );
2190 
2191     // build sorted index array
2192     sal_Int32 nLength = rAttributeSet.getLength();
2193     const PropertyValue* pPairs = rAttributeSet.getConstArray();
2194     sal_Int32* pIndices = new sal_Int32[nLength];
2195     sal_Int32 i;
2196     for( i = 0; i < nLength; i++ )
2197         pIndices[i] = i;
2198     sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
2199 
2200     // create sorted sequences accoring to index array
2201     uno::Sequence< ::rtl::OUString > aNames( nLength );
2202     ::rtl::OUString* pNames = aNames.getArray();
2203     uno::Sequence< uno::Any > aValues( nLength );
2204     uno::Any* pValues = aValues.getArray();
2205     for( i = 0; i < nLength; i++ )
2206     {
2207         const PropertyValue& rVal = pPairs[pIndices[i]];
2208         pNames[i]  = rVal.Name;
2209         pValues[i] = rVal.Value;
2210     }
2211     delete[] pIndices;
2212 
2213     // now set the values
2214     sal_Bool bRet = sal_True;
2215     try
2216     {
2217         xPortion->setPropertyValues( aNames, aValues );
2218     }
2219     catch( UnknownPropertyException e )
2220     {
2221         // error handling through return code!
2222         bRet = sal_False;
2223     }
2224 
2225     return bRet;
2226 }
2227 
2228 sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText )
2229     throw (uno::RuntimeException)
2230 {
2231     return replaceText(0, GetString().getLength(), sText);
2232 }
2233 
2234 //=====  XAccessibleSelection  ============================================
2235 
2236 void SwAccessibleParagraph::selectAccessibleChild(
2237     sal_Int32 nChildIndex )
2238     throw ( lang::IndexOutOfBoundsException,
2239             uno::RuntimeException )
2240 {
2241 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2242 
2243     aSelectionHelper.selectAccessibleChild(nChildIndex);
2244 }
2245 
2246 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
2247     sal_Int32 nChildIndex )
2248     throw ( lang::IndexOutOfBoundsException,
2249             uno::RuntimeException )
2250 {
2251 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2252 
2253     return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
2254 }
2255 
2256 void SwAccessibleParagraph::clearAccessibleSelection(  )
2257     throw ( uno::RuntimeException )
2258 {
2259 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2260 
2261     aSelectionHelper.clearAccessibleSelection();
2262 }
2263 
2264 void SwAccessibleParagraph::selectAllAccessibleChildren(  )
2265     throw ( uno::RuntimeException )
2266 {
2267 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2268 
2269     aSelectionHelper.selectAllAccessibleChildren();
2270 }
2271 
2272 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount(  )
2273     throw ( uno::RuntimeException )
2274 {
2275 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2276 
2277     return aSelectionHelper.getSelectedAccessibleChildCount();
2278 }
2279 
2280 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
2281     sal_Int32 nSelectedChildIndex )
2282     throw ( lang::IndexOutOfBoundsException,
2283             uno::RuntimeException)
2284 {
2285 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2286 
2287     return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
2288 }
2289 
2290 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
2291 void SwAccessibleParagraph::deselectAccessibleChild(
2292     sal_Int32 nChildIndex )
2293     throw ( lang::IndexOutOfBoundsException,
2294             uno::RuntimeException )
2295 {
2296 	CHECK_FOR_DEFUNC( XAccessibleSelection );
2297 
2298     aSelectionHelper.deselectAccessibleChild( nChildIndex );
2299 }
2300 
2301 //=====  XAccessibleHypertext  ============================================
2302 
2303 class SwHyperlinkIter_Impl
2304 {
2305 	const SwpHints *pHints;
2306 	xub_StrLen nStt;
2307 	xub_StrLen nEnd;
2308 	sal_uInt16 nPos;
2309 
2310 public:
2311 	SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm );
2312 	const SwTxtAttr *next();
2313 	sal_uInt16 getCurrHintPos() const { return nPos-1; }
2314 
2315 	xub_StrLen startIdx() const { return nStt; }
2316 	xub_StrLen endIdx() const { return nEnd; }
2317 };
2318 
2319 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) :
2320 	pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ),
2321 	nStt( pTxtFrm->GetOfst() ),
2322 	nPos( 0 )
2323 {
2324 	const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow();
2325 	nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len();
2326 }
2327 
2328 const SwTxtAttr *SwHyperlinkIter_Impl::next()
2329 {
2330 	const SwTxtAttr *pAttr = 0;
2331 	if( pHints )
2332 	{
2333 		while( !pAttr && nPos < pHints->Count() )
2334 		{
2335 			const SwTxtAttr *pHt = (*pHints)[nPos];
2336 			if( RES_TXTATR_INETFMT == pHt->Which() )
2337 			{
2338 				xub_StrLen nHtStt = *pHt->GetStart();
2339 				xub_StrLen nHtEnd = *pHt->GetAnyEnd();
2340 				if( nHtEnd > nHtStt &&
2341 					( (nHtStt >= nStt && nHtStt < nEnd) ||
2342 					  (nHtEnd > nStt && nHtEnd <= nEnd) ) )
2343 				{
2344 					pAttr = pHt;
2345 				}
2346 			}
2347 			++nPos;
2348 		}
2349 	}
2350 
2351 	return pAttr;
2352 };
2353 
2354 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
2355     throw (uno::RuntimeException)
2356 {
2357 	vos::OGuard aGuard(Application::GetSolarMutex());
2358 
2359 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
2360 
2361 	sal_Int32 nCount = 0;
2362     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2363 //    if( !IsEditableState() )
2364     // <--
2365 	{
2366 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2367 		SwHyperlinkIter_Impl aIter( pTxtFrm );
2368 		while( aIter.next() )
2369 			nCount++;
2370 	}
2371 
2372 	return nCount;
2373 }
2374 
2375 uno::Reference< XAccessibleHyperlink > SAL_CALL
2376 	SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
2377     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2378 {
2379 	vos::OGuard aGuard(Application::GetSolarMutex());
2380 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
2381 
2382     uno::Reference< XAccessibleHyperlink > xRet;
2383 
2384     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2385 //    if( !IsEditableState() )
2386     // <--
2387 	{
2388 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2389 		SwHyperlinkIter_Impl aHIter( pTxtFrm );
2390 		while( nLinkIndex-- )
2391 			aHIter.next();
2392 
2393 		const SwTxtAttr *pHt = aHIter.next();
2394 		if( pHt )
2395 		{
2396 			if( !pHyperTextData )
2397 				pHyperTextData = new SwAccessibleHyperTextData;
2398 			SwAccessibleHyperTextData::iterator aIter =
2399 				pHyperTextData ->find( pHt );
2400 			if( aIter != pHyperTextData->end() )
2401 			{
2402 				xRet = (*aIter).second;
2403 			}
2404 			if( !xRet.is() )
2405 			{
2406 				sal_Int32 nHStt= GetPortionData().GetAccessiblePosition(
2407 								max( aHIter.startIdx(), *pHt->GetStart() ) );
2408 				sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition(
2409 								min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
2410 				xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
2411 												  this, nHStt, nHEnd );
2412 				if( aIter != pHyperTextData->end() )
2413 				{
2414 					(*aIter).second = xRet;
2415 				}
2416 				else
2417 				{
2418 					SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
2419 					pHyperTextData->insert( aEntry );
2420 				}
2421 			}
2422 		}
2423 	}
2424 
2425 	if( !xRet.is() )
2426         throw lang::IndexOutOfBoundsException();
2427 
2428 	return xRet;
2429 }
2430 
2431 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
2432     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2433 {
2434 	vos::OGuard aGuard(Application::GetSolarMutex());
2435 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
2436 
2437     // parameter checking
2438     sal_Int32 nLength = GetString().getLength();
2439     if ( ! IsValidPosition( nCharIndex, nLength ) )
2440     {
2441         throw lang::IndexOutOfBoundsException();
2442     }
2443 
2444 	sal_Int32 nRet = -1;
2445     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2446 //    if( !IsEditableState() )
2447     // <--
2448 	{
2449 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2450 		SwHyperlinkIter_Impl aHIter( pTxtFrm );
2451 
2452 		xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex );
2453 		sal_Int32 nPos = 0;
2454 		const SwTxtAttr *pHt = aHIter.next();
2455 		while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) )
2456 		{
2457 			pHt = aHIter.next();
2458 			nPos++;
2459 		}
2460 
2461 		if( pHt )
2462 			nRet = nPos;
2463 
2464 	}
2465 
2466 	return nRet;
2467 }
2468 
2469 // --> OD 2008-05-26 #i71360#
2470 // --> OD 2010-02-22 #i108125# - adjustments for change tracking text markup
2471 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
2472                                         throw (lang::IllegalArgumentException,
2473                                                uno::RuntimeException)
2474 {
2475     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2476     switch ( nTextMarkupType )
2477     {
2478         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2479         case text::TextMarkupType::TRACK_CHANGE_DELETION:
2480         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2481         {
2482             pTextMarkupHelper.reset( new SwTextMarkupHelper(
2483                 GetPortionData(),
2484                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2485         }
2486         break;
2487         default:
2488         {
2489             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2490         }
2491     }
2492 
2493     return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType );
2494 }
2495 
2496 /*accessibility::*/TextSegment SAL_CALL
2497         SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
2498                                               sal_Int32 nTextMarkupType )
2499                                         throw (lang::IndexOutOfBoundsException,
2500                                                lang::IllegalArgumentException,
2501                                                uno::RuntimeException)
2502 {
2503     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2504     switch ( nTextMarkupType )
2505     {
2506         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2507         case text::TextMarkupType::TRACK_CHANGE_DELETION:
2508         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2509         {
2510             pTextMarkupHelper.reset( new SwTextMarkupHelper(
2511                 GetPortionData(),
2512                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2513         }
2514         break;
2515         default:
2516         {
2517             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2518         }
2519     }
2520 
2521     return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
2522 }
2523 
2524 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
2525         SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
2526                                                      sal_Int32 nTextMarkupType )
2527                                         throw (lang::IndexOutOfBoundsException,
2528                                                lang::IllegalArgumentException,
2529                                                uno::RuntimeException)
2530 {
2531     // parameter checking
2532     const sal_Int32 nLength = GetString().getLength();
2533     if ( ! IsValidPosition( nCharIndex, nLength ) )
2534     {
2535         throw lang::IndexOutOfBoundsException();
2536     }
2537 
2538     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2539     switch ( nTextMarkupType )
2540     {
2541         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2542         case text::TextMarkupType::TRACK_CHANGE_DELETION:
2543         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2544         {
2545             pTextMarkupHelper.reset( new SwTextMarkupHelper(
2546                 GetPortionData(),
2547                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2548         }
2549         break;
2550         default:
2551         {
2552             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2553         }
2554     }
2555 
2556     return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
2557 }
2558 // <--
2559 
2560 // --> OD 2008-05-29 #i89175#
2561 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
2562                                         throw (lang::IndexOutOfBoundsException,
2563                                                uno::RuntimeException)
2564 {
2565     // parameter checking
2566     const sal_Int32 nLength = GetString().getLength();
2567     if ( ! IsValidPosition( nIndex, nLength ) )
2568     {
2569         throw lang::IndexOutOfBoundsException();
2570     }
2571 
2572     const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
2573     return nLineNo;
2574 }
2575 
2576 /*accessibility::*/TextSegment SAL_CALL
2577         SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
2578                                         throw (lang::IndexOutOfBoundsException,
2579                                                uno::RuntimeException)
2580 {
2581     // parameter checking
2582     if ( nLineNo < 0 ||
2583          nLineNo >= GetPortionData().GetLineCount() )
2584     {
2585         throw lang::IndexOutOfBoundsException();
2586     }
2587 
2588     i18n::Boundary aLineBound;
2589     GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2590 
2591     /*accessibility::*/TextSegment aTextAtLine;
2592     const ::rtl::OUString rText = GetString();
2593     aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
2594                                           aLineBound.endPos - aLineBound.startPos );
2595     aTextAtLine.SegmentStart = aLineBound.startPos;
2596     aTextAtLine.SegmentEnd = aLineBound.endPos;
2597 
2598     return aTextAtLine;
2599 }
2600 
2601 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
2602                                         throw (uno::RuntimeException)
2603 {
2604     const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
2605 
2606     if ( nLineNoOfCaret >= 0 &&
2607          nLineNoOfCaret < GetPortionData().GetLineCount() )
2608     {
2609         return getTextAtLineNumber( nLineNoOfCaret );
2610     }
2611 
2612     return /*accessibility::*/TextSegment();
2613 }
2614 
2615 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
2616                                         throw (uno::RuntimeException)
2617 {
2618     const sal_Int32 nCaretPos = getCaretPosition();
2619     const sal_Int32 nLength = GetString().getLength();
2620     if ( !IsValidPosition( nCaretPos, nLength ) )
2621     {
2622         return -1;
2623     }
2624 
2625     sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
2626 
2627     // special handling for cursor positioned at end of text line via End key
2628     if ( nCaretPos != 0 )
2629     {
2630         i18n::Boundary aLineBound;
2631         GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2632         if ( nCaretPos == aLineBound.startPos )
2633         {
2634             SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
2635             if ( pCrsrShell != 0 )
2636             {
2637                 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
2638 
2639                 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect();
2640                 // translate core coordinates into accessibility coordinates
2641                 Window *pWin = GetWindow();
2642                 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2643 
2644                 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
2645 
2646                 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2647                 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
2648                 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
2649 
2650                 // convert into AWT Rectangle
2651                 const awt::Rectangle aCursorRect( aScreenRect.Left(),
2652                                                   aScreenRect.Top(),
2653                                                   aScreenRect.GetWidth(),
2654                                                   aScreenRect.GetHeight() );
2655 
2656                 if ( aCharRect.X != aCursorRect.X ||
2657                      aCharRect.Y != aCursorRect.Y )
2658                 {
2659                     --nLineNo;
2660                 }
2661             }
2662         }
2663     }
2664 
2665     return nLineNo;
2666 }
2667 
2668 // --> OD 2010-02-19 #i108125#
2669 void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2670 {
2671     mpParaChangeTrackInfo->reset();
2672 
2673     CheckRegistration( pOld, pNew );
2674 }
2675 // <--
2676