xref: /aoo42x/main/sw/source/core/access/accpara.cxx (revision 4d7c9de0)
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 
60 #include <reffld.hxx>
61 #include <docufld.hxx>
62 #include <expfld.hxx>
63 #include <flddat.hxx>
64 #include <fldui.hrc>
65 #include "../../ui/inc/fldmgr.hxx"
66 #include "fldbas.hxx"      // SwField
67 #include <svl/svstdarr.hxx>
68 #include <unocrsr.hxx>
69 //#include <unoobj.hxx>
70 #include <unoport.hxx>
71 #include <doc.hxx>
72 #include <crsskip.hxx>
73 #include <txtatr.hxx>
74 #include <acchyperlink.hxx>
75 #include <acchypertextdata.hxx>
76 #include <unotools/accessiblerelationsethelper.hxx>
77 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
78 #include <section.hxx>
79 #include <doctxm.hxx>
80 #include <comphelper/accessibletexthelper.hxx>
81 #include <algorithm>
82 #include <docufld.hxx>
83 #include <txtfld.hxx>
84 #include <fmtfld.hxx>
85 #include <modcfg.hxx>
86 //#include "accnote.hxx"
87 #include <com/sun/star/beans/XPropertySet.hpp>
88 #include "swmodule.hxx"
89 #include "redline.hxx"
90 #include <com/sun/star/awt/FontWeight.hpp>
91 #include <com/sun/star/awt/FontStrikeout.hpp>
92 #include <com/sun/star/awt/FontSlant.hpp>
93 #include <wrong.hxx>
94 #include <editeng/brshitem.hxx>
95 #include <swatrset.hxx>
96 #include <frmatr.hxx>
97 #include <unosett.hxx>
98 #include <paratr.hxx>
99 #include <com/sun/star/container/XIndexReplace.hpp>
100 // --> OD 2006-07-12 #i63870#
101 #include <unomap.hxx>
102 #include <unoprnms.hxx>
103 #include <com/sun/star/text/WritingMode2.hpp>
104 #include <editeng/brshitem.hxx>
105 #include <viewimp.hxx>
106 #include <boost/scoped_ptr.hpp>
107 #include <textmarkuphelper.hxx>
108 // --> OD 2010-02-22 #i10825#
109 #include <parachangetrackinginfo.hxx>
110 #include <com/sun/star/text/TextMarkupType.hpp>
111 // <--
112 // --> OD 2010-03-08 #i92233#
113 #include <comphelper/stlunosequence.hxx>
114 // <--
115 
116 #include <algorithm>
117 
118 using namespace ::com::sun::star;
119 using namespace ::com::sun::star::accessibility;
120 using namespace ::com::sun::star::container;
121 using ::rtl::OUString;
122 
123 using beans::PropertyValue;
124 using beans::XMultiPropertySet;
125 using beans::UnknownPropertyException;
126 using beans::PropertyState_DIRECT_VALUE;
127 
128 using std::max;
129 using std::min;
130 using std::sort;
131 
132 namespace com { namespace sun { namespace star {
133     namespace text {
134         class XText;
135     }
136 } } }
137 
138 
139 const sal_Char sServiceName[] = "com.sun.star.text.AccessibleParagraphView";
140 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView";
141 const xub_StrLen MAX_DESC_TEXT_LEN = 40;
142 const SwTxtNode* SwAccessibleParagraph::GetTxtNode() const
143 {
144     const SwFrm* pFrm = GetFrm();
145     DBG_ASSERT( pFrm->IsTxtFrm(), "The text frame has mutated!" );
146 
147     const SwTxtNode* pNode = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode();
148     DBG_ASSERT( pNode != NULL, "A text frame without a text node." );
149 
150     return pNode;
151 }
152 
153 ::rtl::OUString SwAccessibleParagraph::GetString()
154 {
155     return GetPortionData().GetAccessibleString();
156 }
157 
158 ::rtl::OUString SwAccessibleParagraph::GetDescription()
159 {
160     // --> OD 2004-09-29 #117933# - provide empty description for paragraphs
161     return ::rtl::OUString();
162     // <--
163 }
164 
165 sal_Int32 SwAccessibleParagraph::GetCaretPos()
166 {
167     sal_Int32 nRet = -1;
168 
169     // get the selection's point, and test whether it's in our node
170     // --> OD 2005-12-20 #i27301# - consider adjusted method signature
171     SwPaM* pCaret = GetCursor( false );  // caret is first PaM in PaM-ring
172     // <--
173     if( pCaret != NULL )
174     {
175         const SwTxtNode* pNode = GetTxtNode();
176 
177         // check whether the point points into 'our' node
178         SwPosition* pPoint = pCaret->GetPoint();
179         if( pNode->GetIndex() == pPoint->nNode.GetIndex() )
180         {
181             // same node? Then check whether it's also within 'our' part
182             // of the paragraph
183             sal_uInt16 nIndex = pPoint->nContent.GetIndex();
184 			if(!GetPortionData().IsValidCorePosition( nIndex ) ||
185 				( GetPortionData().IsZeroCorePositionData() && nIndex== 0) )
186 			{
187 				SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() );
188 				bool bFormat = (pTxtFrm && pTxtFrm->HasPara());
189 				if(bFormat)
190 				{
191 					ClearPortionData();
192 					UpdatePortionData();
193 				}
194 			}
195             if( GetPortionData().IsValidCorePosition( nIndex ) )
196             {
197                 // Yes, it's us!
198                 // --> OD 2006-10-19 #70538#
199                 // consider that cursor/caret is in front of the list label
200                 if ( pCaret->IsInFrontOfLabel() )
201                 {
202                     nRet = 0;
203                 }
204                 else
205                 {
206                     nRet = GetPortionData().GetAccessiblePosition( nIndex );
207                 }
208                 // <--
209 
210                 DBG_ASSERT( nRet >= 0, "invalid cursor?" );
211                 DBG_ASSERT( nRet <= GetPortionData().GetAccessibleString().
212                                               getLength(), "invalid cursor?" );
213             }
214             // else: in this paragraph, but in different frame
215         }
216         // else: not in this paragraph
217     }
218     // else: no cursor -> no caret
219 
220     return nRet;
221 }
222 
223 sal_Bool SwAccessibleParagraph::GetSelection(
224     sal_Int32& nStart, sal_Int32& nEnd)
225 {
226     sal_Bool bRet = sal_False;
227     nStart = -1;
228     nEnd = -1;
229 
230     // get the selection, and test whether it affects our text node
231     // --> OD 2005-12-20 #i27301# - consider adjusted method signature
232     SwPaM* pCrsr = GetCursor( true );
233     // <--
234     if( pCrsr != NULL )
235     {
236         // get SwPosition for my node
237         const SwTxtNode* pNode = GetTxtNode();
238         sal_uLong nHere = pNode->GetIndex();
239 
240         // iterate over ring
241         SwPaM* pRingStart = pCrsr;
242         do
243         {
244             // ignore, if no mark
245             if( pCrsr->HasMark() )
246             {
247                 // check whether nHere is 'inside' pCrsr
248                 SwPosition* pStart = pCrsr->Start();
249                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
250                 SwPosition* pEnd = pCrsr->End();
251                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
252                 if( ( nHere >= nStartIndex ) &&
253                     ( nHere <= nEndIndex )      )
254                 {
255                     // translate start and end positions
256 
257                     // start position
258                     sal_Int32 nLocalStart = -1;
259                     if( nHere > nStartIndex )
260                     {
261                         // selection starts in previous node:
262                         // then our local selection starts with the paragraph
263                         nLocalStart = 0;
264                     }
265                     else
266                     {
267                         DBG_ASSERT( nHere == nStartIndex,
268                                     "miscalculated index" );
269 
270                         // selection starts in this node:
271                         // then check whether it's before or inside our part of
272                         // the paragraph, and if so, get the proper position
273                         sal_uInt16 nCoreStart = pStart->nContent.GetIndex();
274                         if( nCoreStart <
275                             GetPortionData().GetFirstValidCorePosition() )
276                         {
277                             nLocalStart = 0;
278                         }
279                         else if( nCoreStart <=
280                                  GetPortionData().GetLastValidCorePosition() )
281                         {
282                             DBG_ASSERT(
283                                 GetPortionData().IsValidCorePosition(
284                                                                   nCoreStart ),
285                                  "problem determining valid core position" );
286 
287                             nLocalStart =
288                                 GetPortionData().GetAccessiblePosition(
289                                                                   nCoreStart );
290                         }
291                     }
292 
293                     // end position
294                     sal_Int32 nLocalEnd = -1;
295                     if( nHere < nEndIndex )
296                     {
297                         // selection ends in following node:
298                         // then our local selection extends to the end
299                         nLocalEnd = GetPortionData().GetAccessibleString().
300                                                                    getLength();
301                     }
302                     else
303                     {
304                         DBG_ASSERT( nHere == nEndIndex,
305                                     "miscalculated index" );
306 
307                         // selection ends in this node: then select everything
308                         // before our part of the node
309                         sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex();
310                         if( nCoreEnd >
311                                 GetPortionData().GetLastValidCorePosition() )
312                         {
313                             // selection extends beyond out part of this para
314                             nLocalEnd = GetPortionData().GetAccessibleString().
315                                                                    getLength();
316                         }
317                         else if( nCoreEnd >=
318                                  GetPortionData().GetFirstValidCorePosition() )
319                         {
320                             // selection is inside our part of this para
321                             DBG_ASSERT(
322                                 GetPortionData().IsValidCorePosition(
323                                                                   nCoreEnd ),
324                                  "problem determining valid core position" );
325 
326                             nLocalEnd = GetPortionData().GetAccessiblePosition(
327                                                                    nCoreEnd );
328                         }
329                     }
330 
331                     if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
332                     {
333                         nStart = nLocalStart;
334                         nEnd = nLocalEnd;
335                         bRet = sal_True;
336                     }
337                 }
338                 // else: this PaM doesn't point to this paragraph
339             }
340             // else: this PaM is collapsed and doesn't select anything
341 
342             // next PaM in ring
343             pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
344         }
345         while( !bRet && (pCrsr != pRingStart) );
346     }
347     // else: nocursor -> no selection
348 
349     return bRet;
350 }
351 
352 // --> OD 2005-12-20 #i27301# - new parameter <_bForSelection>
353 SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection )
354 {
355     // get the cursor shell; if we don't have any, we don't have a
356     // cursor/selection either
357     SwPaM* pCrsr = NULL;
358     SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
359     // --> OD 2005-12-20 #i27301#
360     // - if cursor is retrieved for selection, the cursors for a table selection
361     //   has to be returned.
362     if ( pCrsrShell != NULL &&
363          ( _bForSelection || !pCrsrShell->IsTableMode() ) )
364     // <--
365     {
366 		SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell )
367 							? static_cast< SwFEShell * >( pCrsrShell ) : 0;
368 		if( !pFESh ||
369 			!(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) )
370 		{
371 			// get the selection, and test whether it affects our text node
372 			pCrsr = pCrsrShell->GetCrsr( sal_False /* ??? */ );
373 		}
374     }
375 
376     return pCrsr;
377 }
378 
379 sal_Bool SwAccessibleParagraph::IsHeading() const
380 {
381 	const SwTxtNode *pTxtNd = GetTxtNode();
382 	return pTxtNd->IsOutline();
383 }
384 
385 void SwAccessibleParagraph::GetStates(
386 		::utl::AccessibleStateSetHelper& rStateSet )
387 {
388 	SwAccessibleContext::GetStates( rStateSet );
389 
390 	// MULTILINE
391 	rStateSet.AddState( AccessibleStateType::MULTI_LINE );
392 
393 	// MULTISELECTABLE
394 	SwCrsrShell *pCrsrSh = GetCrsrShell();
395 	if( pCrsrSh )
396 		rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
397 
398 	// FOCUSABLE
399 	if( pCrsrSh )
400 		rStateSet.AddState( AccessibleStateType::FOCUSABLE );
401 
402 	// FOCUSED (simulates node index of cursor)
403     // --> OD 2005-12-20 #i27301# - consider adjusted method signature
404     SwPaM* pCaret = GetCursor( false );
405     // <--
406 	const SwTxtNode* pTxtNd = GetTxtNode();
407 	if( pCaret != 0 && pTxtNd != 0 &&
408 		pTxtNd->GetIndex() == pCaret->GetPoint()->nNode.GetIndex() &&
409 		nOldCaretPos != -1)
410 	{
411 		Window *pWin = GetWindow();
412 		if( pWin && pWin->HasFocus() )
413 			rStateSet.AddState( AccessibleStateType::FOCUSED );
414 		::vos::ORef < SwAccessibleContext > xThis( this );
415 		GetMap()->SetCursorContext( xThis );
416 	}
417 }
418 
419 void SwAccessibleParagraph::_InvalidateContent( sal_Bool bVisibleDataFired )
420 {
421     ::rtl::OUString sOldText( GetString() );
422 
423 	ClearPortionData();
424 
425     const ::rtl::OUString& rText = GetString();
426 
427 	if( rText != sOldText )
428 	{
429 		// The text is changed
430 		AccessibleEventObject aEvent;
431 		aEvent.EventId = AccessibleEventId::TEXT_CHANGED;
432 
433         // determine exact changes between sOldText and rText
434         comphelper::OCommonAccessibleText::implInitTextChangedEvent(
435             sOldText, rText,
436             aEvent.OldValue, aEvent.NewValue );
437 
438 		FireAccessibleEvent( aEvent );
439 		uno::Reference< XAccessible > xparent = getAccessibleParent();
440 		uno::Reference< XAccessibleContext > xAccContext(xparent,uno::UNO_QUERY);
441 		if (xAccContext.is() && xAccContext->getAccessibleRole() == AccessibleRole::TABLE_CELL)
442 		{
443 			SwAccessibleContext* pPara = static_cast< SwAccessibleContext* >(xparent.get());
444 			if(pPara)
445 			{
446 				AccessibleEventObject aParaEvent;
447 				aParaEvent.EventId = AccessibleEventId::VALUE_CHANGED;
448 				pPara->FireAccessibleEvent(aParaEvent);
449 			}
450 		}
451 	}
452 	else if( !bVisibleDataFired )
453 	{
454 		FireVisibleDataEvent();
455 	}
456 
457 	sal_Bool bNewIsHeading = IsHeading();
458 	//Get the real heading level, Heading1 ~ Heading10
459 	nHeadingLevel = GetRealHeadingLevel();
460 	sal_Bool bOldIsHeading;
461 	{
462 		vos::OGuard aGuard( aMutex );
463 		bOldIsHeading = bIsHeading;
464 		if( bIsHeading != bNewIsHeading )
465 			bIsHeading = bNewIsHeading;
466 	}
467 
468 
469 	if( bNewIsHeading != bOldIsHeading || rText != sOldText )
470 	{
471         ::rtl::OUString sNewDesc( GetDescription() );
472         ::rtl::OUString sOldDesc;
473 		{
474 			vos::OGuard aGuard( aMutex );
475 			sOldDesc = sDesc;
476 			if( sDesc != sNewDesc )
477 				sDesc = sNewDesc;
478 		}
479 
480 		if( sNewDesc != sOldDesc )
481 		{
482 			// The text is changed
483 			AccessibleEventObject aEvent;
484 			aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
485 			aEvent.OldValue <<= sOldDesc;
486 			aEvent.NewValue <<= sNewDesc;
487 
488 			FireAccessibleEvent( aEvent );
489 		}
490 	}
491 }
492 
493 void SwAccessibleParagraph::_InvalidateCursorPos()
494 {
495 	// The text is changed
496 	sal_Int32 nNew = GetCaretPos();
497 	sal_Int32 nOld;
498 	{
499 		vos::OGuard aGuard( aMutex );
500 		nOld = nOldCaretPos;
501 		nOldCaretPos = nNew;
502 	}
503 	if( -1 != nNew )
504 	{
505 		// remember that object as the one that has the caret. This is
506 		// neccessary to notify that object if the cursor leaves it.
507 		::vos::ORef < SwAccessibleContext > xThis( this );
508 		GetMap()->SetCursorContext( xThis );
509 	}
510 
511 	Window *pWin = GetWindow();
512 	if( nOld != nNew )
513 	{
514 		// The cursor's node position is sumilated by the focus!
515 		if( pWin && pWin->HasFocus() && -1 == nOld )
516 			FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True );
517 
518 
519 		AccessibleEventObject aEvent;
520 		aEvent.EventId = AccessibleEventId::CARET_CHANGED;
521 		aEvent.OldValue <<= nOld;
522 		aEvent.NewValue <<= nNew;
523 
524 		FireAccessibleEvent( aEvent );
525 
526 		if( pWin && pWin->HasFocus() && -1 == nNew )
527 			FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_False );
528 		//To send TEXT_SELECTION_CHANGED event
529 		sal_Int32 nStart=0;
530 		sal_Int32 nEnd  =0;
531 		sal_Bool bCurSelection=GetSelection(nStart,nEnd);
532 		if(m_bLastHasSelection || bCurSelection )
533 		{
534 			aEvent.EventId = AccessibleEventId::TEXT_SELECTION_CHANGED;
535 			aEvent.OldValue <<= uno::Any();
536 			aEvent.NewValue <<= uno::Any();
537 			FireAccessibleEvent(aEvent);
538 		}
539 		m_bLastHasSelection =bCurSelection;
540 	}
541 }
542 
543 void SwAccessibleParagraph::_InvalidateFocus()
544 {
545 	Window *pWin = GetWindow();
546 	if( pWin )
547 	{
548 		sal_Int32 nPos;
549 		{
550 			vos::OGuard aGuard( aMutex );
551 			nPos = nOldCaretPos;
552 		}
553 		ASSERT( nPos != -1, "focus object should be selected" );
554 
555 		FireStateChangedEvent( AccessibleStateType::FOCUSED,
556 							   pWin->HasFocus() && nPos != -1 );
557 	}
558 }
559 
560 SwAccessibleParagraph::SwAccessibleParagraph(
561         SwAccessibleMap& rInitMap,
562         const SwTxtFrm& rTxtFrm )
563     // --> OD 2010-02-24 #i108125#
564     : SwClient( const_cast<SwTxtNode*>(rTxtFrm.GetTxtNode()) )
565     // <--
566     , SwAccessibleContext( &rInitMap, AccessibleRole::PARAGRAPH, &rTxtFrm )
567     , sDesc()
568     , pPortionData( NULL )
569     , pHyperTextData( NULL )
570     , nOldCaretPos( -1 )
571     , bIsHeading( sal_False )
572     //Get the real heading level, Heading1 ~ Heading10
573     , nHeadingLevel (-1)
574     , aSelectionHelper( *this )
575     // --> OD 2010-02-19 #i108125#
576     , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTxtFrm ) )
577     // <--
578     , m_bLastHasSelection(false)  //To add TEXT_SELECTION_CHANGED event
579 {
580 	vos::OGuard aGuard(Application::GetSolarMutex());
581 
582 	bIsHeading = IsHeading();
583 	//Get the real heading level, Heading1 ~ Heading10
584 	nHeadingLevel = GetRealHeadingLevel();
585     // --> OD 2004-09-27 #117970# - set an empty accessibility name for paragraphs
586     SetName( ::rtl::OUString() );
587     // <--
588 
589 	// If this object has the focus, then it is remembered by the map itself.
590 	// not necessary to remember this pos here. Generally, the pos will be updated in invalidateXXX method, which may fire the
591 	//Focus event based on the difference of new & old caret pos.
592 	//nOldCaretPos = GetCaretPos();
593 }
594 
595 SwAccessibleParagraph::~SwAccessibleParagraph()
596 {
597 	vos::OGuard aGuard(Application::GetSolarMutex());
598 
599     delete pPortionData;
600     delete pHyperTextData;
601     // --> OD 2010-02-22 #i108125#
602     delete mpParaChangeTrackInfo;
603     // <--
604 }
605 
606 sal_Bool SwAccessibleParagraph::HasCursor()
607 {
608 	vos::OGuard aGuard( aMutex );
609 	return nOldCaretPos != -1;
610 }
611 
612 void SwAccessibleParagraph::UpdatePortionData()
613     throw( uno::RuntimeException )
614 {
615     // obtain the text frame
616     DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
617     DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
618     const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
619 
620     // build new portion data
621     delete pPortionData;
622     pPortionData = new SwAccessiblePortionData(
623         pFrm->GetTxtNode(), GetMap()->GetShell()->GetViewOptions() );
624     pFrm->VisitPortions( *pPortionData );
625 
626     DBG_ASSERT( pPortionData != NULL, "UpdatePortionData() failed" );
627 }
628 
629 void SwAccessibleParagraph::ClearPortionData()
630 {
631     delete pPortionData;
632     pPortionData = NULL;
633 
634 	delete pHyperTextData;
635 	pHyperTextData = 0;
636 }
637 
638 
639 void SwAccessibleParagraph::ExecuteAtViewShell( sal_uInt16 nSlot )
640 {
641     DBG_ASSERT( GetMap() != NULL, "no map?" );
642     ViewShell* pViewShell = GetMap()->GetShell();
643 
644     DBG_ASSERT( pViewShell != NULL, "View shell exptected!" );
645     SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell();
646 
647     DBG_ASSERT( pSfxShell != NULL, "SfxViewShell shell exptected!" );
648     if( !pSfxShell )
649 		return;
650 
651 	SfxViewFrame *pFrame = pSfxShell->GetViewFrame();
652     DBG_ASSERT( pFrame != NULL, "View frame exptected!" );
653 	if( !pFrame )
654 		return;
655 
656 	SfxDispatcher *pDispatcher = pFrame->GetDispatcher();
657     DBG_ASSERT( pDispatcher != NULL, "Dispatcher exptected!" );
658 	if( !pDispatcher )
659 		return;
660 
661 	pDispatcher->Execute( nSlot );
662 }
663 
664 SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion(
665     sal_Int32 nStartIndex,
666     sal_Int32 nEndIndex )
667 {
668     DBG_ASSERT( (IsValidChar(nStartIndex, GetString().getLength()) &&
669                  (nEndIndex == -1)) ||
670                 IsValidRange(nStartIndex, nEndIndex, GetString().getLength()),
671                 "please check parameters before calling this method" );
672 
673     sal_uInt16 nStart = GetPortionData().GetModelPosition( nStartIndex );
674     sal_uInt16 nEnd = (nEndIndex == -1) ? (nStart + 1) :
675                         GetPortionData().GetModelPosition( nEndIndex );
676 
677     // create UNO cursor
678     SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() );
679     SwIndex aIndex( pTxtNode, nStart );
680     SwPosition aStartPos( *pTxtNode, aIndex );
681     SwUnoCrsr* pUnoCursor = pTxtNode->GetDoc()->CreateUnoCrsr( aStartPos );
682     pUnoCursor->SetMark();
683     pUnoCursor->GetMark()->nContent = nEnd;
684 
685     // create a (dummy) text portion to be returned
686     uno::Reference<text::XText> aEmpty;
687     SwXTextPortion* pPortion =
688         new SwXTextPortion ( pUnoCursor, aEmpty, PORTION_TEXT);
689     delete pUnoCursor;
690 
691     return pPortion;
692 }
693 
694 
695 //
696 // range checking for parameter
697 //
698 
699 sal_Bool SwAccessibleParagraph::IsValidChar(
700     sal_Int32 nPos, sal_Int32 nLength)
701 {
702     return (nPos >= 0) && (nPos < nLength);
703 }
704 
705 sal_Bool SwAccessibleParagraph::IsValidPosition(
706     sal_Int32 nPos, sal_Int32 nLength)
707 {
708     return (nPos >= 0) && (nPos <= nLength);
709 }
710 
711 sal_Bool SwAccessibleParagraph::IsValidRange(
712     sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength)
713 {
714     return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength);
715 }
716 SwTOXSortTabBase* SwAccessibleParagraph::GetTOXSortTabBase()
717 {
718 	const SwTxtNode* pTxtNd = GetTxtNode();
719 	if( pTxtNd )
720 	{
721 		const SwSectionNode * pSectNd = pTxtNd->FindSectionNode();
722 		if( pSectNd )
723 		{
724 			const SwSection * pSect = &pSectNd->GetSection();
725 			SwTOXBaseSection *pTOXBaseSect = (SwTOXBaseSection *)pSect;
726 			if( pSect->GetType() == TOX_CONTENT_SECTION )
727 			{
728 				SwTOXSortTabBase* pSortBase = 0;
729 				int nSize = pTOXBaseSect->GetTOXSortTabBases()->Count();
730 
731 				for(int nIndex = 0; nIndex<nSize; nIndex++ )
732 				{
733 					pSortBase = (*(pTOXBaseSect->GetTOXSortTabBases()))[nIndex];
734 					if( pSortBase->pTOXNd == pTxtNd )
735 						break;
736 				}
737 
738 				if (pSortBase)
739 				{
740 					return pSortBase;
741 				}
742 			}
743 		}
744 	}
745 	return NULL;
746 }
747 
748 short SwAccessibleParagraph::GetTOCLevel()
749 {
750 	SwTOXSortTabBase* pToxBase = GetTOXSortTabBase();
751 	if( pToxBase )
752 	{
753 		const SwCntntNode*	pNd = pToxBase->aTOXSources[0].pNd;
754 		if( pNd )
755 			return pToxBase->GetLevel();
756 		else
757 			return -1;
758 	}
759 	else
760 		return -1;
761 }
762 
763 //the function is to check whether the position is in a redline range.
764 const SwRedline* SwAccessibleParagraph::GetRedlineAtIndex( sal_Int32 )
765 {
766 	const SwRedline* pRedline = NULL;
767 	SwPaM* pCrSr = GetCursor( true );
768 	if ( pCrSr )
769 	{
770 		SwPosition* pStart = pCrSr->Start();
771 		const SwTxtNode* pNode = GetTxtNode();
772 		if ( pNode )
773 		{
774 			const SwDoc* pDoc = pNode->GetDoc();
775 			if ( pDoc )
776 			{
777 				pRedline = pDoc->GetRedline( *pStart, NULL );
778 			}
779 		}
780 	}
781 
782 	return pRedline;
783 }
784 
785 //
786 // text boundaries
787 //
788 
789 
790 sal_Bool SwAccessibleParagraph::GetCharBoundary(
791     i18n::Boundary& rBound,
792     const ::rtl::OUString&,
793     sal_Int32 nPos )
794 {
795     if( GetPortionData().FillBoundaryIFDateField( rBound,  nPos) )
796 		return sal_True;
797 
798     rBound.startPos = nPos;
799     rBound.endPos = nPos+1;
800     return sal_True;
801 }
802 
803 sal_Bool SwAccessibleParagraph::GetWordBoundary(
804     i18n::Boundary& rBound,
805     const ::rtl::OUString& rText,
806     sal_Int32 nPos )
807 {
808     sal_Bool bRet = sal_False;
809 
810     // now ask the Break-Iterator for the word
811     DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
812     DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
813     if( pBreakIt->GetBreakIter().is() )
814     {
815         // get locale for this position
816         sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos );
817         lang::Locale aLocale = pBreakIt->GetLocale(
818                               GetTxtNode()->GetLang( nModelPos ) );
819 
820         // which type of word are we interested in?
821         // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.)
822         const sal_uInt16 nWordType = i18n::WordType::ANY_WORD;
823 
824 /*
825 		// get word boundary, as the Break-Iterator sees fit.
826 		sal_Unicode SpaceChar(' ');
827 		if (rText.getCodePointAt(nPos) == SpaceChar)
828 		{
829 			int nStartPos = nPos;
830 			int nEndPos = nPos+1;
831 			while (nStartPos >= 0 && rText.getCodePointAt(nStartPos) == SpaceChar)
832 				--nStartPos;
833 			while (nEndPos < rText.getLength() && rText.getCodePointAt(nEndPos) == SpaceChar)
834 				++nEndPos;
835 			//Get the previous word boundary + the followed space characters
836 			if (nStartPos >= 0)
837 			{
838 				rBound = pBreakIt->xBreak->getWordBoundary( rText, nStartPos, aLocale, nWordType, sal_True );
839 				rBound.endPos += (nEndPos-nStartPos - 1);
840 			}
841 			//When the frontal characters are whitespace, return the all space characters directly.
842 			else
843 			{
844 				rBound.startPos = 0;
845 				rBound.endPos = nEndPos;
846 			}
847 		}
848 		// add the " " into the word boundry
849 		else
850 		{
851 			rBound = pBreakIt->xBreak->getWordBoundary(rText, nPos, aLocale, nWordType, sal_True );
852 			sal_Int32 nEndPos = rBound.endPos, nLength = rText.getLength();
853 			while ( nEndPos < nLength && rText.getCodePointAt(nEndPos) == SpaceChar )
854 				nEndPos++;
855 			rBound.endPos = nEndPos;
856 		}
857 		tabCharInWord( nPos, rBound);
858 		if( GetPortionData().FillBoundaryIFDateField( rBound,  rBound.startPos) )
859 			return sal_True;
860         return sal_True; // MT: So why do we need the return TRUE above???
861 */
862         // get word boundary, as the Break-Iterator sees fit.
863         rBound = pBreakIt->GetBreakIter()->getWordBoundary(
864             rText, nPos, aLocale, nWordType, sal_True );
865 
866         // It's a word if the first character is an alpha-numeric character.
867         bRet = GetAppCharClass().isLetterNumeric(
868             rText.getStr()[ rBound.startPos ] );
869     }
870     else
871     {
872         // no break Iterator -> no word
873         rBound.startPos = nPos;
874         rBound.endPos = nPos;
875     }
876 
877     return bRet;
878 }
879 
880 sal_Bool SwAccessibleParagraph::GetSentenceBoundary(
881     i18n::Boundary& rBound,
882     const ::rtl::OUString& rText,
883     sal_Int32 nPos )
884 {
885 	const sal_Unicode* pStr = rText.getStr();
886 	if (pStr)
887 	{
888 		while( pStr[nPos] == sal_Unicode(' ') && nPos < rText.getLength())
889 			nPos++;
890 	}
891     GetPortionData().GetSentenceBoundary( rBound, nPos );
892     return sal_True;
893 }
894 
895 sal_Bool SwAccessibleParagraph::GetLineBoundary(
896     i18n::Boundary& rBound,
897     const ::rtl::OUString& rText,
898     sal_Int32 nPos )
899 {
900 	if( rText.getLength() == nPos )
901 		GetPortionData().GetLastLineBoundary( rBound );
902 	else
903 		GetPortionData().GetLineBoundary( rBound, nPos );
904     return sal_True;
905 }
906 
907 sal_Bool SwAccessibleParagraph::GetParagraphBoundary(
908     i18n::Boundary& rBound,
909     const ::rtl::OUString& rText,
910     sal_Int32 )
911 {
912     rBound.startPos = 0;
913     rBound.endPos = rText.getLength();
914     return sal_True;
915 }
916 
917 sal_Bool SwAccessibleParagraph::GetAttributeBoundary(
918     i18n::Boundary& rBound,
919     const ::rtl::OUString&,
920     sal_Int32 nPos )
921 {
922     GetPortionData().GetAttributeBoundary( rBound, nPos );
923     return sal_True;
924 }
925 
926 sal_Bool SwAccessibleParagraph::GetGlyphBoundary(
927     i18n::Boundary& rBound,
928     const ::rtl::OUString& rText,
929     sal_Int32 nPos )
930 {
931     sal_Bool bRet = sal_False;
932 
933     // ask the Break-Iterator for the glyph by moving one cell
934     // forward, and then one cell back
935     DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
936     DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
937     if( pBreakIt->GetBreakIter().is() )
938     {
939         // get locale for this position
940         sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos );
941         lang::Locale aLocale = pBreakIt->GetLocale(
942                               GetTxtNode()->GetLang( nModelPos ) );
943 
944         // get word boundary, as the Break-Iterator sees fit.
945         const sal_uInt16 nIterMode = i18n::CharacterIteratorMode::SKIPCELL;
946         sal_Int32 nDone = 0;
947         rBound.endPos = pBreakIt->GetBreakIter()->nextCharacters(
948              rText, nPos, aLocale, nIterMode, 1, nDone );
949         rBound.startPos = pBreakIt->GetBreakIter()->previousCharacters(
950              rText, rBound.endPos, aLocale, nIterMode, 1, nDone );
951 
952         bRet = ((rBound.startPos <= nPos) && (nPos <= rBound.endPos));
953         DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" );
954         DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" );
955     }
956     else
957     {
958         // no break Iterator -> no glyph
959         rBound.startPos = nPos;
960         rBound.endPos = nPos;
961     }
962 
963     return bRet;
964 }
965 
966 
967 sal_Bool SwAccessibleParagraph::GetTextBoundary(
968     i18n::Boundary& rBound,
969     const ::rtl::OUString& rText,
970     sal_Int32 nPos,
971     sal_Int16 nTextType )
972     throw (
973         lang::IndexOutOfBoundsException,
974         lang::IllegalArgumentException,
975         uno::RuntimeException)
976 {
977     // error checking
978     if( !( AccessibleTextType::LINE == nTextType
979 				? IsValidPosition( nPos, rText.getLength() )
980 				: IsValidChar( nPos, rText.getLength() ) ) )
981         throw lang::IndexOutOfBoundsException();
982 
983     sal_Bool bRet;
984 
985     switch( nTextType )
986     {
987         case AccessibleTextType::WORD:
988             bRet = GetWordBoundary( rBound, rText, nPos );
989             break;
990 
991         case AccessibleTextType::SENTENCE:
992             bRet = GetSentenceBoundary( rBound, rText, nPos );
993             break;
994 
995         case AccessibleTextType::PARAGRAPH:
996             bRet = GetParagraphBoundary( rBound, rText, nPos );
997             break;
998 
999         case AccessibleTextType::CHARACTER:
1000             bRet = GetCharBoundary( rBound, rText, nPos );
1001             break;
1002 
1003         case AccessibleTextType::LINE:
1004             //Solve the problem of returning wrong LINE and PARAGRAPH
1005             if((nPos == rText.getLength()) && nPos > 0)
1006             	bRet = GetLineBoundary( rBound, rText, nPos - 1);
1007             else
1008             	bRet = GetLineBoundary( rBound, rText, nPos );
1009             break;
1010 
1011         case AccessibleTextType::ATTRIBUTE_RUN:
1012             bRet = GetAttributeBoundary( rBound, rText, nPos );
1013 			if(bRet)
1014 			{
1015 				SwCrsrShell* pCrsrShell = GetCrsrShell();
1016 				if( pCrsrShell != NULL && pCrsrShell->GetViewOptions() && pCrsrShell->GetViewOptions()->IsOnlineSpell())
1017 				{
1018 					SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() );
1019 					if(pTxtNode)
1020 					{
1021 						const SwWrongList* pWrongList = pTxtNode->GetWrong();
1022 						if( NULL != pWrongList )
1023 						{
1024 							xub_StrLen nBegin = nPos;
1025 							xub_StrLen nLen = 1;
1026 							const xub_StrLen nNext = pWrongList->NextWrong(nBegin);
1027 							xub_StrLen nLast;
1028                             xub_StrLen nWrongPos = pWrongList->GetWrongPos( nBegin );
1029                             if ( nWrongPos >= pWrongList->Count() ||
1030                                  ( nLast = pWrongList->Pos( nWrongPos ) ) >= nBegin )
1031                             {
1032                                 nLast = nWrongPos
1033                                         ? pWrongList->Pos( --nWrongPos )
1034                                         : STRING_LEN;
1035                             }
1036                             if ( nBegin > pWrongList->GetBeginInv() &&
1037                                  ( nLast == STRING_LEN || nLast < pWrongList->GetEndInv() ) )
1038                             {
1039                                 nLast = nBegin > pWrongList->GetEndInv()
1040                                         ? pWrongList->GetEndInv()
1041                                         : nBegin;
1042                             }
1043                             else if ( nLast < STRING_LEN )
1044                             {
1045                                 nLast += pWrongList->Len( nWrongPos );
1046                             }
1047 							//
1048 							sal_Bool bIn = pWrongList->InWrongWord(nBegin,nLen); // && !pTxtNode->IsSymbol(nBegin) )
1049 							if(bIn)
1050 							{
1051 								rBound.startPos = max(nNext,(xub_StrLen)rBound.startPos);
1052 								rBound.endPos = min(xub_StrLen(nNext + nLen),(xub_StrLen)rBound.endPos);
1053 							}
1054 							else
1055 							{
1056 								if (STRING_LEN == nLast)//first
1057 								{
1058 									rBound.endPos = min(nNext,(xub_StrLen)rBound.endPos);
1059 								}
1060 								else if(STRING_LEN == nNext)
1061 								{
1062 									rBound.startPos = max(nLast,(xub_StrLen)rBound.startPos);
1063 								}
1064 								else
1065 								{
1066 									rBound.startPos = max(nLast,(xub_StrLen)rBound.startPos);
1067 									rBound.endPos = min(nNext,(xub_StrLen)rBound.endPos);
1068 								}
1069 							}
1070 						}
1071 					}
1072 				}
1073 			}
1074             break;
1075 
1076         case AccessibleTextType::GLYPH:
1077             bRet = GetGlyphBoundary( rBound, rText, nPos );
1078             break;
1079 
1080         default:
1081             throw lang::IllegalArgumentException( );
1082     }
1083 
1084     return bRet;
1085 }
1086 
1087 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void)
1088         throw (uno::RuntimeException)
1089 {
1090 	vos::OGuard aGuard(Application::GetSolarMutex());
1091 
1092 	CHECK_FOR_DEFUNC( XAccessibleContext );
1093 
1094 	vos::OGuard aGuard2( aMutex );
1095 	if( !sDesc.getLength() )
1096 		sDesc = GetDescription();
1097 
1098     return sDesc;
1099 }
1100 
1101 lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void)
1102         throw (IllegalAccessibleComponentStateException, uno::RuntimeException)
1103 {
1104 	vos::OGuard aGuard(Application::GetSolarMutex());
1105 
1106 	SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() );
1107 	if( !pTxtFrm )
1108 	{
1109 		THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" );
1110 	}
1111 
1112 	const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode();
1113     lang::Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) );
1114 
1115 	return aLoc;
1116 }
1117 
1118 /** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
1119 
1120     OD 2005-12-02 #i27138#
1121 
1122     @author OD
1123 */
1124 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
1125     throw ( uno::RuntimeException )
1126 {
1127     vos::OGuard aGuard(Application::GetSolarMutex());
1128     CHECK_FOR_DEFUNC( XAccessibleContext );
1129 
1130     utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
1131 
1132     const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm());
1133     ASSERT( pTxtFrm,
1134             "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame");
1135     if ( pTxtFrm )
1136     {
1137         const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) );
1138         if ( pPrevCntFrm )
1139         {
1140             uno::Sequence< uno::Reference<XInterface> > aSequence(1);
1141             aSequence[0] = GetMap()->GetContext( pPrevCntFrm );
1142             AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
1143                                         aSequence );
1144             pHelper->AddRelation( aAccRel );
1145         }
1146 
1147         const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) );
1148         if ( pNextCntFrm )
1149         {
1150             uno::Sequence< uno::Reference<XInterface> > aSequence(1);
1151             aSequence[0] = GetMap()->GetContext( pNextCntFrm );
1152             AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
1153                                         aSequence );
1154             pHelper->AddRelation( aAccRel );
1155         }
1156     }
1157 
1158     return pHelper;
1159 }
1160 
1161 void SAL_CALL SwAccessibleParagraph::grabFocus()
1162         throw (uno::RuntimeException)
1163 {
1164 	vos::OGuard aGuard(Application::GetSolarMutex());
1165 
1166 	CHECK_FOR_DEFUNC( XAccessibleContext );
1167 
1168     // get cursor shell
1169 	SwCrsrShell *pCrsrSh = GetCrsrShell();
1170     // --> OD 2005-12-20 #i27301# - consider new method signature
1171     SwPaM *pCrsr = GetCursor( false );
1172     // <--
1173 	const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
1174 	const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode();
1175 
1176     if( pCrsrSh != 0 && pTxtNd != 0 &&
1177 		( pCrsr == 0 ||
1178 	 	  pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() ||
1179 		  !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) )
1180     {
1181         // create pam for selection
1182         SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ),
1183 						pTxtFrm->GetOfst() );
1184         SwPosition aStartPos( *pTxtNd, aIndex );
1185         SwPaM aPaM( aStartPos );
1186 
1187         // set PaM at cursor shell
1188 		Select( aPaM );
1189 
1190 
1191     }
1192 
1193     /* ->#i13955# */
1194     Window * pWindow = GetWindow();
1195 
1196     if (pWindow != NULL)
1197         pWindow->GrabFocus();
1198     /* <-#i13955# */
1199 }
1200 
1201 // --> OD 2007-01-17 #i71385#
1202 bool lcl_GetBackgroundColor( Color & rColor,
1203                              const SwFrm* pFrm,
1204                              SwCrsrShell* pCrsrSh )
1205 {
1206     const SvxBrushItem* pBackgrdBrush = 0;
1207     const Color* pSectionTOXColor = 0;
1208     SwRect aDummyRect;
1209     if ( pFrm &&
1210          pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) )
1211     {
1212         if ( pSectionTOXColor )
1213         {
1214             rColor = *pSectionTOXColor;
1215             return true;
1216         }
1217         else
1218         {
1219             rColor =  pBackgrdBrush->GetColor();
1220             return true;
1221         }
1222     }
1223     else if ( pCrsrSh )
1224     {
1225         rColor = pCrsrSh->Imp()->GetRetoucheColor();
1226         return true;
1227     }
1228 
1229     return false;
1230 }
1231 
1232 sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground()
1233                                 throw (uno::RuntimeException)
1234 {
1235     Color aBackgroundCol;
1236 
1237     if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
1238     {
1239         if ( aBackgroundCol.IsDark() )
1240         {
1241             return COL_WHITE;
1242         }
1243         else
1244         {
1245             return COL_BLACK;
1246         }
1247     }
1248 
1249     return SwAccessibleContext::getForeground();
1250 }
1251 
1252 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
1253                                 throw (uno::RuntimeException)
1254 {
1255     Color aBackgroundCol;
1256 
1257     if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
1258     {
1259         return aBackgroundCol.GetColor();
1260     }
1261 
1262     return SwAccessibleContext::getBackground();
1263 }
1264 // <--
1265 
1266 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getImplementationName()
1267         throw( uno::RuntimeException )
1268 {
1269     return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
1270 }
1271 
1272 sal_Bool SAL_CALL SwAccessibleParagraph::supportsService(
1273 		const ::rtl::OUString& sTestServiceName)
1274     throw (uno::RuntimeException)
1275 {
1276 	return sTestServiceName.equalsAsciiL( sServiceName,
1277 										  sizeof(sServiceName)-1 ) ||
1278 		   sTestServiceName.equalsAsciiL( sAccessibleServiceName,
1279 				   						  sizeof(sAccessibleServiceName)-1 );
1280 }
1281 
1282 uno::Sequence< ::rtl::OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames()
1283         throw( uno::RuntimeException )
1284 {
1285     uno::Sequence< ::rtl::OUString > aRet(2);
1286     ::rtl::OUString* pArray = aRet.getArray();
1287     pArray[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
1288     pArray[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
1289 	return aRet;
1290 }
1291 
1292 uno::Sequence< ::rtl::OUString > getAttributeNames()
1293 {
1294     static uno::Sequence< ::rtl::OUString >* pNames = NULL;
1295 
1296     if( pNames == NULL )
1297     {
1298         // Add the font name to attribute list
1299         uno::Sequence< ::rtl::OUString >* pSeq = new uno::Sequence< ::rtl::OUString >( 13 );
1300 
1301         ::rtl::OUString* pStrings = pSeq->getArray();
1302 
1303         // sorted list of strings
1304         sal_Int32 i = 0;
1305 
1306 #define STR(x) pStrings[i++] = OUString::createFromAscii(x)
1307         STR( GetPropName( UNO_NAME_CHAR_BACK_COLOR ).pName );
1308         STR( GetPropName( UNO_NAME_CHAR_COLOR ).pName );
1309        	STR( GetPropName( UNO_NAME_CHAR_CONTOURED ).pName );
1310 		STR( GetPropName( UNO_NAME_CHAR_EMPHASIS ).pName );
1311         STR( GetPropName( UNO_NAME_CHAR_ESCAPEMENT ).pName );
1312         STR( GetPropName( UNO_NAME_CHAR_FONT_NAME ).pName );
1313         STR( GetPropName( UNO_NAME_CHAR_HEIGHT ).pName );
1314         STR( GetPropName( UNO_NAME_CHAR_POSTURE ).pName );
1315         STR( GetPropName( UNO_NAME_CHAR_SHADOWED ).pName );
1316         STR( GetPropName( UNO_NAME_CHAR_STRIKEOUT ).pName );
1317         STR( GetPropName( UNO_NAME_CHAR_UNDERLINE ).pName );
1318 		STR( GetPropName( UNO_NAME_CHAR_UNDERLINE_COLOR ).pName );
1319         STR( GetPropName( UNO_NAME_CHAR_WEIGHT ).pName );
1320 #undef STR
1321         DBG_ASSERT( i == pSeq->getLength(), "Please adjust length" );
1322         if( i != pSeq->getLength() )
1323             pSeq->realloc( i );
1324         pNames = pSeq;
1325     }
1326     return *pNames;
1327 }
1328 
1329 uno::Sequence< ::rtl::OUString > getSupplementalAttributeNames()
1330 {
1331     static uno::Sequence< ::rtl::OUString >* pNames = NULL;
1332 
1333     if( pNames == NULL )
1334     {
1335         uno::Sequence< ::rtl::OUString >* pSeq = new uno::Sequence< ::rtl::OUString >( 9 );
1336 
1337         ::rtl::OUString* pStrings = pSeq->getArray();
1338 
1339         // sorted list of strings
1340         sal_Int32 i = 0;
1341 
1342 #define STR(x) pStrings[i++] = OUString::createFromAscii(x)
1343         STR( GetPropName( UNO_NAME_NUMBERING_LEVEL ).pName );
1344 		STR( GetPropName( UNO_NAME_NUMBERING_RULES ).pName );
1345         STR( GetPropName( UNO_NAME_PARA_ADJUST ).pName );
1346         STR( GetPropName( UNO_NAME_PARA_BOTTOM_MARGIN ).pName );
1347         STR( GetPropName( UNO_NAME_PARA_FIRST_LINE_INDENT ).pName );
1348         STR( GetPropName( UNO_NAME_PARA_LEFT_MARGIN ).pName );
1349         STR( GetPropName( UNO_NAME_PARA_LINE_SPACING ).pName );
1350         STR( GetPropName( UNO_NAME_PARA_RIGHT_MARGIN ).pName );
1351         STR( GetPropName( UNO_NAME_TABSTOPS ).pName );
1352 #undef STR
1353         DBG_ASSERT( i == pSeq->getLength(), "Please adjust length" );
1354         if( i != pSeq->getLength() )
1355             pSeq->realloc( i );
1356         pNames = pSeq;
1357     }
1358     return *pNames;
1359 }
1360 //
1361 //=====  XInterface  =======================================================
1362 //
1363 
1364 uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType )
1365     throw (uno::RuntimeException)
1366 {
1367     uno::Any aRet;
1368     if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) )
1369     {
1370         uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity
1371         aRet <<= aAccText;
1372     }
1373     else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) )
1374     {
1375         uno::Reference<XAccessibleEditableText> aAccEditText = this;
1376         aRet <<= aAccEditText;
1377     }
1378     else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) )
1379     {
1380         uno::Reference<XAccessibleSelection> aAccSel = this;
1381         aRet <<= aAccSel;
1382     }
1383     else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) )
1384     {
1385         uno::Reference<XAccessibleHypertext> aAccHyp = this;
1386         aRet <<= aAccHyp;
1387     }
1388     // --> OD 2006-07-13 #i63870#
1389     // add interface com::sun:star:accessibility::XAccessibleTextAttributes
1390     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) )
1391     {
1392         uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
1393         aRet <<= aAccTextAttr;
1394     }
1395     // <--
1396     // --> OD 2008-06-10 #i89175#
1397     // add interface com::sun:star:accessibility::XAccessibleTextMarkup
1398     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) )
1399     {
1400         uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this;
1401         aRet <<= aAccTextMarkup;
1402     }
1403     // add interface com::sun:star:accessibility::XAccessibleMultiLineText
1404     else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) )
1405     {
1406         uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this;
1407         aRet <<= aAccMultiLineText;
1408     }
1409     // <--
1410 	//MSAA Extension Implementation in app  module
1411     else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextSelection> *)NULL) )
1412     {
1413         uno::Reference< com::sun::star::accessibility::XAccessibleTextSelection > aTextExtension = this;
1414         aRet <<= aTextExtension;
1415     }
1416 	else if ( rType == ::getCppuType((uno::Reference<XAccessibleExtendedAttributes> *)NULL) )
1417     {
1418 		uno::Reference<XAccessibleExtendedAttributes> xAttr = this;
1419         aRet <<= xAttr;
1420     }
1421     else
1422     {
1423         aRet = SwAccessibleContext::queryInterface(rType);
1424     }
1425 
1426     return aRet;
1427 }
1428 
1429 //====== XTypeProvider ====================================================
1430 uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException)
1431 {
1432     uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
1433 
1434 	sal_Int32 nIndex = aTypes.getLength();
1435     // --> OD 2006-07-13 #i63870#
1436     // add type accessibility::XAccessibleTextAttributes
1437     // --> OD 2008-06-10 #i89175#
1438     // add type accessibility::XAccessibleTextMarkup and accessibility::XAccessibleMultiLineText
1439     aTypes.realloc( nIndex + 6 );
1440 
1441     uno::Type* pTypes = aTypes.getArray();
1442 	pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) );
1443     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) );
1444 	pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) );
1445     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) );
1446     pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) );
1447 	pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) );
1448     // <--
1449 
1450 	return aTypes;
1451 }
1452 
1453 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId()
1454         throw(uno::RuntimeException)
1455 {
1456     vos::OGuard aGuard(Application::GetSolarMutex());
1457     static uno::Sequence< sal_Int8 > aId( 16 );
1458     static sal_Bool bInit = sal_False;
1459     if(!bInit)
1460     {
1461         rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
1462         bInit = sal_True;
1463     }
1464     return aId;
1465 }
1466 
1467 
1468 //
1469 //=====  XAccesibleText  ===================================================
1470 //
1471 
1472 sal_Int32 SwAccessibleParagraph::getCaretPosition()
1473     throw (uno::RuntimeException)
1474 {
1475 	vos::OGuard aGuard(Application::GetSolarMutex());
1476 
1477 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1478 
1479     sal_Int32 nRet = GetCaretPos();
1480 	{
1481         vos::OGuard aOldCaretPosGuard( aMutex );
1482 		ASSERT( nRet == nOldCaretPos, "caret pos out of sync" );
1483 		nOldCaretPos = nRet;
1484 	}
1485 	if( -1 != nRet )
1486 	{
1487 		::vos::ORef < SwAccessibleContext > xThis( this );
1488 		GetMap()->SetCursorContext( xThis );
1489 	}
1490 
1491     return nRet;
1492 }
1493 
1494 sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
1495     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1496 {
1497 	vos::OGuard aGuard(Application::GetSolarMutex());
1498 
1499 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1500 
1501     // parameter checking
1502     sal_Int32 nLength = GetString().getLength();
1503     if ( ! IsValidPosition( nIndex, nLength ) )
1504     {
1505         throw lang::IndexOutOfBoundsException();
1506     }
1507 
1508     sal_Bool bRet = sal_False;
1509 
1510     // get cursor shell
1511     SwCrsrShell* pCrsrShell = GetCrsrShell();
1512     if( pCrsrShell != NULL )
1513     {
1514         // create pam for selection
1515         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1516         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex));
1517         SwPosition aStartPos( *pNode, aIndex );
1518         SwPaM aPaM( aStartPos );
1519 
1520         // set PaM at cursor shell
1521         bRet = Select( aPaM );
1522     }
1523 
1524     return bRet;
1525 }
1526 
1527 sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex )
1528     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1529 {
1530 	vos::OGuard aGuard(Application::GetSolarMutex());
1531 
1532 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1533 
1534     ::rtl::OUString sText( GetString() );
1535 
1536     // return character (if valid)
1537     if( IsValidChar(nIndex, sText.getLength() ) )
1538     {
1539         return sText.getStr()[nIndex];
1540     }
1541     else
1542         throw lang::IndexOutOfBoundsException();
1543 }
1544 
1545 com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > SwAccessibleParagraph::GetCurrentTabStop( sal_Int32 nIndex  )
1546 {
1547 vos::OGuard aGuard(Application::GetSolarMutex());
1548 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1549 
1550 
1551 
1552     /*  #i12332# The position after the string needs special treatment.
1553         IsValidChar -> IsValidPosition
1554     */
1555     if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
1556         throw lang::IndexOutOfBoundsException();
1557 
1558     /*  #i12332#  */
1559     sal_Bool bBehindText = sal_False;
1560     if ( nIndex == GetString().getLength() )
1561         bBehindText = sal_True;
1562 
1563     // get model position & prepare GetCharRect() arguments
1564     SwCrsrMoveState aMoveState;
1565     aMoveState.bRealHeight = sal_True;
1566     aMoveState.bRealWidth = sal_True;
1567     SwSpecialPos aSpecialPos;
1568     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1569 
1570     sal_uInt16 nPos = 0;
1571 
1572     /*  #i12332# FillSpecialPos does not accept nIndex ==
1573          GetString().getLength(). In that case nPos is set to the
1574          length of the string in the core. This way GetCharRect
1575          returns the rectangle for a cursor at the end of the
1576          paragraph. */
1577     if (bBehindText)
1578     {
1579         nPos = pNode->GetTxt().Len();
1580     }
1581     else
1582         nPos = GetPortionData().FillSpecialPos
1583             (nIndex, aSpecialPos, aMoveState.pSpecialPos );
1584 
1585     // call GetCharRect
1586     SwRect aCoreRect;
1587     SwIndex aIndex( pNode, nPos );
1588     SwPosition aPosition( *pNode, aIndex );
1589     GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
1590 
1591 	// already get the caret postion
1592 
1593 	/*SwFrm* pTFrm = const_cast<SwFrm*>(GetFrm());
1594 	com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > tabs =
1595 		pTFrm->GetTabStopInfo(aCoreRect.Left());*/
1596 
1597 	com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > tabs;
1598 	const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
1599 	if( nStrLen > 0 )
1600 	{
1601 		SwFrm* pTFrm = const_cast<SwFrm*>(GetFrm());
1602 		tabs = pTFrm->GetTabStopInfo(aCoreRect.Left());
1603 	}
1604 
1605 	if( tabs.hasElements() )
1606 	{
1607 		// translate core coordinates into accessibility coordinates
1608 		Window *pWin = GetWindow();
1609 		CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1610 
1611 		SwRect aTmpRect(0, 0, tabs[0].Position, 0);
1612 
1613 		Rectangle aScreenRect( GetMap()->CoreToPixel( aTmpRect.SVRect() ));
1614         SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
1615 
1616 		Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
1617 		aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
1618 
1619 		tabs[0].Position = aScreenRect.GetWidth();
1620 	}
1621 
1622 	return tabs;
1623 }
1624 
1625 struct IndexCompare
1626 {
1627 	const PropertyValue* pValues;
1628 	IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
1629 	bool operator() ( const sal_Int32& a, const sal_Int32& b ) const
1630 	{
1631 		return (pValues[a].Name < pValues[b].Name) ? true : false;
1632 	}
1633 };
1634 
1635 String SwAccessibleParagraph::GetFieldTypeNameAtIndex(sal_Int32 nIndex)
1636 {
1637 	String strTypeName;
1638 	SwFldMgr aMgr;
1639 	SwTxtFld* pTxtFld = NULL;
1640 	SwTxtNode* pTxtNd = const_cast<SwTxtNode*>( GetTxtNode() );
1641 	SwIndex fldIndex( pTxtNd, nIndex );
1642 	sal_Int32 nFldIndex = GetPortionData().GetFieldIndex(nIndex);
1643 	if (nFldIndex >= 0)
1644 	{
1645 		const SwpHints* pSwpHints = GetTxtNode()->GetpSwpHints();
1646 		if (pSwpHints)
1647 		{
1648 			const sal_uInt16  nSize = pSwpHints ? pSwpHints->Count() : 0;
1649 			for( sal_uInt16 i = 0; i < nSize; ++i )
1650 			{
1651 				const SwTxtAttr* pHt = (*pSwpHints)[i];
1652 				if (pHt->Which() == RES_TXTATR_FIELD && (nFldIndex-- == 0))
1653 				{
1654 					pTxtFld = (SwTxtFld *)pHt;
1655 					break;
1656 				}
1657 				else if (pHt->Which() == RES_TXTATR_REFMARK && (nFldIndex-- == 0))
1658 					strTypeName = String(OUString(RTL_CONSTASCII_USTRINGPARAM("set reference")));
1659 			}
1660 		}
1661 	}
1662 	if (pTxtFld)
1663 	{
1664 		const SwField* pField = (pTxtFld->GetFmtFld()).GetField();
1665 		if (pField)
1666 		{
1667 			strTypeName = pField->GetTyp()->GetTypeStr(pField->GetTypeId());
1668 			sal_uInt16 nWhich = pField->GetTyp()->Which();
1669 			rtl::OUString sEntry;
1670 			sal_Int32 subType = 0;
1671 			switch (nWhich)
1672 			{
1673 			case RES_DOCSTATFLD:
1674 				subType = ((SwDocStatField*)pField)->GetSubType();
1675 				break;
1676 			case RES_GETREFFLD:
1677 				{
1678 					sal_uInt16 nSub = pField->GetSubType();
1679 					switch( nSub )
1680 					{
1681 					case REF_BOOKMARK:
1682 						{
1683 							const SwGetRefField* pRefFld = dynamic_cast<const SwGetRefField*>(pField);
1684 							if ( pRefFld && pRefFld->IsRefToHeadingCrossRefBookmark() )
1685 								sEntry = OUString(RTL_CONSTASCII_USTRINGPARAM("Headings"));
1686 							else if ( pRefFld && pRefFld->IsRefToNumItemCrossRefBookmark() )
1687 								sEntry = OUString(RTL_CONSTASCII_USTRINGPARAM("Numbered Paragraphs"));
1688 							else
1689 								sEntry = OUString(RTL_CONSTASCII_USTRINGPARAM("Bookmarks"));
1690 						}
1691 						break;
1692 					case REF_FOOTNOTE:
1693 						sEntry = OUString(RTL_CONSTASCII_USTRINGPARAM("Footnotes"));
1694 						break;
1695 					case REF_ENDNOTE:
1696 						sEntry = OUString(RTL_CONSTASCII_USTRINGPARAM("Endnotes"));
1697 						break;
1698 					case REF_SETREFATTR:
1699 						sEntry = OUString(RTL_CONSTASCII_USTRINGPARAM("Insert Reference"));
1700 						break;
1701 					case REF_SEQUENCEFLD:
1702 						sEntry = ((SwGetRefField*)pField)->GetSetRefName();
1703 						break;
1704 					}
1705 					//Get format string
1706 					strTypeName = sEntry;
1707                     // <pField->GetFormat() >= 0> is always true as <pField->GetFormat()> is unsigned
1708 //                    if (pField->GetFormat() >= 0)
1709 					{
1710 						sEntry = aMgr.GetFormatStr( pField->GetTypeId(), pField->GetFormat() );
1711 						if (sEntry.getLength() > 0)
1712 						{
1713 							strTypeName.AppendAscii("-");
1714 							strTypeName += String(sEntry);
1715 						}
1716 					}
1717 				}
1718 				break;
1719 			case RES_DATETIMEFLD:
1720 				subType = ((SwDateTimeField*)pField)->GetSubType();
1721 				break;
1722 			case RES_JUMPEDITFLD:
1723 				{
1724 					sal_uInt16 nFormat= pField->GetFormat();
1725 					sal_uInt16 nSize = aMgr.GetFormatCount(pField->GetTypeId(), sal_False);
1726 					if (nFormat < nSize)
1727 					{
1728 						sEntry = aMgr.GetFormatStr(pField->GetTypeId(), nFormat);
1729 						if (sEntry.getLength() > 0)
1730 						{
1731 							strTypeName.AppendAscii("-");
1732 							strTypeName += String(sEntry);
1733 						}
1734 					}
1735 				}
1736 				break;
1737 			case RES_EXTUSERFLD:
1738 				subType = ((SwExtUserField*)pField)->GetSubType();
1739 				break;
1740 			case RES_HIDDENTXTFLD:
1741 			case RES_SETEXPFLD:
1742 				{
1743 					sEntry = pField->GetTyp()->GetName();
1744 					if (sEntry.getLength() > 0)
1745 					{
1746 						strTypeName.AppendAscii("-");
1747 						strTypeName += String(sEntry);
1748 					}
1749 				}
1750 				break;
1751 			case RES_DOCINFOFLD:
1752 				subType = pField->GetSubType();
1753 				subType &= 0x00ff;
1754 				break;
1755 			case RES_REFPAGESETFLD:
1756 				{
1757 					SwRefPageSetField* pRPld = (SwRefPageSetField*)pField;
1758 					sal_Bool bOn = pRPld->IsOn();
1759 					strTypeName.AppendAscii("-");
1760 					if (bOn)
1761 						strTypeName += String(OUString(RTL_CONSTASCII_USTRINGPARAM("on")));
1762 					else
1763 						strTypeName += String(OUString(RTL_CONSTASCII_USTRINGPARAM("off")));
1764 				}
1765 				break;
1766 			case RES_AUTHORFLD:
1767 				{
1768 					strTypeName.AppendAscii("-");
1769 					strTypeName += aMgr.GetFormatStr(pField->GetTypeId(), pField->GetFormat() & 0xff);
1770 				}
1771 				break;
1772 			}
1773 			if (subType > 0 || (subType == 0 && (nWhich == RES_DOCINFOFLD || nWhich == RES_EXTUSERFLD || nWhich == RES_DOCSTATFLD)))
1774 			{
1775 				SvStringsDtor aLst;
1776 				aMgr.GetSubTypes(pField->GetTypeId(), aLst);
1777 				if (subType < aLst.Count())
1778 					sEntry = *aLst[subType];
1779 				if (sEntry.getLength() > 0)
1780 				{
1781 					if (nWhich == RES_DOCINFOFLD)
1782 					{
1783 						strTypeName = String(sEntry);
1784 						sal_uInt32 nSize = aMgr.GetFormatCount(pField->GetTypeId(), sal_False);
1785 						sal_uInt16 nExSub = pField->GetSubType() & 0xff00;
1786 						if (nSize > 0 && nExSub > 0)
1787 						{
1788 							//Get extra subtype string
1789 							strTypeName.AppendAscii("-");
1790 							sEntry = aMgr.GetFormatStr(pField->GetTypeId(), nExSub/0x0100-1);
1791 							strTypeName += String(sEntry);
1792 						}
1793 					}
1794 					else
1795 					{
1796 						strTypeName.AppendAscii("-");
1797 						strTypeName += String(sEntry);
1798 					}
1799 				}
1800 			}
1801 		}
1802 	}
1803 	return strTypeName;
1804 }
1805 // --> OD 2006-07-20 #i63870#
1806 // re-implement method on behalf of methods <_getDefaultAttributesImpl(..)> and
1807 // <_getRunAttributesImpl(..)>
1808 uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes(
1809     sal_Int32 nIndex,
1810     const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1811     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1812 {
1813 
1814 	vos::OGuard aGuard(Application::GetSolarMutex());
1815 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1816 
1817     const ::rtl::OUString& rText = GetString();
1818 
1819     if( ! IsValidChar( nIndex, rText.getLength()+1 ) )        throw lang::IndexOutOfBoundsException();
1820 
1821 	bool bSupplementalMode = false;
1822     uno::Sequence< ::rtl::OUString > aNames = aRequestedAttributes;
1823 	if (aNames.getLength() == 0)
1824 	{
1825 		bSupplementalMode = true;
1826 		aNames = getAttributeNames();
1827 	}
1828     // retrieve default character attributes
1829     tAccParaPropValMap aDefAttrSeq;
1830     _getDefaultAttributesImpl( aNames, aDefAttrSeq, true );
1831 
1832     // retrieved run character attributes
1833     tAccParaPropValMap aRunAttrSeq;
1834     _getRunAttributesImpl( nIndex, aNames, aRunAttrSeq );
1835 
1836     // merge default and run attributes
1837     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1838     PropertyValue* pValues = aValues.getArray();
1839     sal_Int32 i = 0;
1840     for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin();
1841           aDefIter != aDefAttrSeq.end();
1842           ++aDefIter )
1843     {
1844         tAccParaPropValMap::const_iterator aRunIter =
1845                                         aRunAttrSeq.find( aDefIter->first );
1846         if ( aRunIter != aRunAttrSeq.end() )
1847         {
1848             pValues[i] = aRunIter->second;
1849         }
1850         else
1851         {
1852             pValues[i] = aDefIter->second;
1853         }
1854         ++i;
1855     }
1856 	if( bSupplementalMode )
1857 	{
1858         uno::Sequence< ::rtl::OUString > aSupplementalNames = aRequestedAttributes;
1859 		if (aSupplementalNames.getLength() == 0)
1860 			aSupplementalNames = getSupplementalAttributeNames();
1861 
1862 		tAccParaPropValMap aSupplementalAttrSeq;
1863 		_getSupplementalAttributesImpl( nIndex, aSupplementalNames, aSupplementalAttrSeq );
1864 
1865 		aValues.realloc( aValues.getLength() + aSupplementalAttrSeq.size() );
1866 		pValues = aValues.getArray();
1867 
1868 		for ( tAccParaPropValMap::const_iterator aSupplementalIter = aSupplementalAttrSeq.begin();
1869 			aSupplementalIter != aSupplementalAttrSeq.end();
1870 			++aSupplementalIter )
1871 		{
1872 			pValues[i] = aSupplementalIter->second;
1873 			++i;
1874 		}
1875 
1876 		_correctValues( nIndex, aValues );
1877 
1878 		aValues.realloc( aValues.getLength() + 1 );
1879 
1880 		pValues = aValues.getArray();
1881 
1882 		const SwTxtNode* pTxtNode( GetTxtNode() );
1883 		PropertyValue& rValue = pValues[aValues.getLength() - 1 ];
1884 		rValue.Name = OUString::createFromAscii("NumberingPrefix");
1885 		OUString sNumBullet = pTxtNode->GetNumString();
1886 		rValue.Value <<= sNumBullet;
1887 		rValue.Handle = -1;
1888 		rValue.State = PropertyState_DIRECT_VALUE;
1889 
1890 		String strTypeName = GetFieldTypeNameAtIndex(nIndex);
1891 		if (strTypeName.Len() > 0)
1892 		{
1893 			aValues.realloc( aValues.getLength() + 1 );
1894 			pValues = aValues.getArray();
1895 			rValue = pValues[aValues.getLength() - 1];
1896 			rValue.Name = OUString::createFromAscii("FieldType");
1897 			rValue.Value <<= rtl::OUString(strTypeName.ToLowerAscii());
1898 			rValue.Handle = -1;
1899 			rValue.State = PropertyState_DIRECT_VALUE;
1900 		}
1901 
1902 		//sort property values
1903 		// build sorted index array
1904 		sal_Int32 nLength = aValues.getLength();
1905 		const PropertyValue* pPairs = aValues.getConstArray();
1906 		sal_Int32* pIndices = new sal_Int32[nLength];
1907 		for( i = 0; i < nLength; i++ )
1908 			pIndices[i] = i;
1909 		sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
1910 		// create sorted sequences accoring to index array
1911         uno::Sequence<PropertyValue> aNewValues( nLength );
1912 		PropertyValue* pNewValues = aNewValues.getArray();
1913 		for( i = 0; i < nLength; i++ )
1914 		{
1915 			pNewValues[i] = pPairs[pIndices[i]];
1916 		}
1917 		delete[] pIndices;
1918 		return aNewValues;
1919 	}
1920 
1921 //    // create a (dummy) text portion for the sole purpose of calling
1922 //    // getPropertyValues on it
1923 //    Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 );
1924 
1925 //    // get values
1926 //    Sequence<OUString> aNames = getAttributeNames();
1927 //    sal_Int32 nLength = aNames.getLength();
1928 //    Sequence<Any> aAnys( nLength );
1929 //    aAnys = xPortion->getPropertyValues( aNames );
1930 
1931 //    // copy names + anys into return sequence
1932 //    Sequence<PropertyValue> aValues( aNames.getLength() );
1933 //    const OUString* pNames = aNames.getConstArray();
1934 //    const Any* pAnys = aAnys.getConstArray();
1935 //    PropertyValue* pValues = aValues.getArray();
1936 //    for( sal_Int32 i = 0; i < nLength; i++ )
1937 //    {
1938 //        PropertyValue& rValue = pValues[i];
1939 //        rValue.Name = pNames[i];
1940 //        rValue.Value = pAnys[i];
1941 //        rValue.Handle = -1;                         // handle not supported
1942 //        rValue.State = PropertyState_DIRECT_VALUE;  // states not supported
1943 //    }
1944 
1945 //    // adjust background color if we're in a gray portion
1946 //    DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name.
1947 //                equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")),
1948 //                "Please adjust CHAR_BACK_COLOR_POS constant." );
1949 //    if( GetPortionData().IsInGrayPortion( nIndex ) )
1950 //        pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
1951 
1952     return aValues;
1953 }
1954 
1955 // --> OD 2006-07-11 #i63870#
1956 void SwAccessibleParagraph::_getDefaultAttributesImpl(
1957         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1958         tAccParaPropValMap& rDefAttrSeq,
1959         const bool bOnlyCharAttrs )
1960 {
1961     // retrieve default attributes
1962     const SwTxtNode* pTxtNode( GetTxtNode() );
1963     ::boost::scoped_ptr<SfxItemSet> pSet;
1964     if ( !bOnlyCharAttrs )
1965     {
1966         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1967                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1968                                RES_PARATR_BEGIN, RES_PARATR_END - 1,
1969                                RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1970                                0 ) );
1971     }
1972     else
1973     {
1974         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1975                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1976                                0 ) );
1977     }
1978     // --> OD 2007-11-12 #i82637#
1979     // From the perspective of the a11y API the default character attributes
1980     // are the character attributes, which are set at the paragraph style
1981     // of the paragraph. The character attributes set at the automatic paragraph
1982     // style of the paragraph are treated as run attributes.
1983 //    pTxtNode->SwCntntNode::GetAttr( *pSet );
1984     // get default paragraph attributes, if needed, and merge these into <pSet>
1985     if ( !bOnlyCharAttrs )
1986     {
1987         SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1988                              RES_PARATR_BEGIN, RES_PARATR_END - 1,
1989                              RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1990                              0 );
1991         pTxtNode->SwCntntNode::GetAttr( aParaSet );
1992         pSet->Put( aParaSet );
1993     }
1994     // get default character attributes and merge these into <pSet>
1995     ASSERT( pTxtNode->GetTxtColl(),
1996             "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" );
1997     if ( pTxtNode->GetTxtColl() )
1998     {
1999         SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
2000                              RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
2001                              0 );
2002         aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() );
2003         pSet->Put( aCharSet );
2004     }
2005     // <--
2006 
2007     // build-up sequence containing the run attributes <rDefAttrSeq>
2008     tAccParaPropValMap aDefAttrSeq;
2009     {
2010         const SfxItemPropertyMap* pPropMap =
2011                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
2012         PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
2013         PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
2014         while ( aPropIt != aPropertyEntries.end() )
2015         {
2016             const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID );
2017             if ( pItem )
2018             {
2019                 uno::Any aVal;
2020                 pItem->QueryValue( aVal, aPropIt->nMemberId );
2021 
2022                 PropertyValue rPropVal;
2023                 rPropVal.Name = aPropIt->sName;
2024                 rPropVal.Value = aVal;
2025                 rPropVal.Handle = -1;
2026                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2027 
2028                 aDefAttrSeq[rPropVal.Name] = rPropVal;
2029             }
2030             ++aPropIt;
2031         }
2032 
2033         // --> OD 2007-01-15 #i72800#
2034         // add property value entry for the paragraph style
2035         if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() )
2036         {
2037             const ::rtl::OUString sParaStyleName =
2038                     ::rtl::OUString::createFromAscii(
2039                             GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName );
2040             if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() )
2041             {
2042                 PropertyValue rPropVal;
2043                 rPropVal.Name = sParaStyleName;
2044                 uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) );
2045                 rPropVal.Value = aVal;
2046                 rPropVal.Handle = -1;
2047                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2048 
2049                 aDefAttrSeq[rPropVal.Name] = rPropVal;
2050             }
2051         }
2052         // <--
2053 
2054         // --> OD 2007-01-15 #i73371#
2055         // resolve value text::WritingMode2::PAGE of property value entry WritingMode
2056         if ( !bOnlyCharAttrs && GetFrm() )
2057         {
2058             const ::rtl::OUString sWritingMode =
2059                     ::rtl::OUString::createFromAscii(
2060                             GetPropName( UNO_NAME_WRITING_MODE ).pName );
2061             tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode );
2062             if ( aIter != aDefAttrSeq.end() )
2063             {
2064                 PropertyValue rPropVal( aIter->second );
2065                 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
2066                 if ( nVal == text::WritingMode2::PAGE )
2067                 {
2068                     const SwFrm* pUpperFrm( GetFrm()->GetUpper() );
2069                     while ( pUpperFrm )
2070                     {
2071                         if ( pUpperFrm->GetType() &
2072                                ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) )
2073                         {
2074                             if ( pUpperFrm->IsVertical() )
2075                             {
2076                                 nVal = text::WritingMode2::TB_RL;
2077                             }
2078                             else if ( pUpperFrm->IsRightToLeft() )
2079                             {
2080                                 nVal = text::WritingMode2::RL_TB;
2081                             }
2082                             else
2083                             {
2084                                 nVal = text::WritingMode2::LR_TB;
2085                             }
2086                             rPropVal.Value <<= nVal;
2087                             aDefAttrSeq[rPropVal.Name] = rPropVal;
2088                             break;
2089                         }
2090 
2091                         if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) )
2092                         {
2093                             pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm();
2094                         }
2095                         else
2096                         {
2097                             pUpperFrm = pUpperFrm->GetUpper();
2098                         }
2099                     }
2100                 }
2101             }
2102         }
2103         // <--
2104     }
2105 
2106     if ( aRequestedAttributes.getLength() == 0 )
2107     {
2108         rDefAttrSeq = aDefAttrSeq;
2109     }
2110     else
2111     {
2112         const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
2113         const sal_Int32 nLength = aRequestedAttributes.getLength();
2114         for( sal_Int32 i = 0; i < nLength; ++i )
2115         {
2116             tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] );
2117             if ( aIter != aDefAttrSeq.end() )
2118             {
2119                 rDefAttrSeq[ aIter->first ] = aIter->second;
2120             }
2121         }
2122     }
2123 }
2124 
2125 uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
2126         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
2127         throw ( uno::RuntimeException )
2128 {
2129     vos::OGuard aGuard(Application::GetSolarMutex());
2130     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2131 
2132     tAccParaPropValMap aDefAttrSeq;
2133     _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
2134 
2135     // --> OD 2010-03-08 #i92233#
2136     static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "MMToPixelRatio" ) );
2137     bool bProvideMMToPixelRatio( false );
2138     {
2139         if ( aRequestedAttributes.getLength() == 0 )
2140         {
2141             bProvideMMToPixelRatio = true;
2142         }
2143         else
2144         {
2145             const rtl::OUString* aRequestedAttrIter =
2146                   ::std::find( ::comphelper::stl_begin( aRequestedAttributes ),
2147                                ::comphelper::stl_end( aRequestedAttributes ),
2148                                sMMToPixelRatio );
2149             if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) )
2150             {
2151                 bProvideMMToPixelRatio = true;
2152             }
2153         }
2154     }
2155     // <--
2156 
2157     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() +
2158                                             ( bProvideMMToPixelRatio ? 1 : 0 ) );
2159     PropertyValue* pValues = aValues.getArray();
2160     sal_Int32 i = 0;
2161     for ( tAccParaPropValMap::const_iterator aIter  = aDefAttrSeq.begin();
2162           aIter != aDefAttrSeq.end();
2163           ++aIter )
2164     {
2165         pValues[i] = aIter->second;
2166         ++i;
2167     }
2168 
2169     // --> OD 2010-03-08 #i92233#
2170     if ( bProvideMMToPixelRatio )
2171     {
2172         PropertyValue rPropVal;
2173         rPropVal.Name = sMMToPixelRatio;
2174         const Size a100thMMSize( 1000, 1000 );
2175         const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize );
2176         const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width();
2177         rPropVal.Value = uno::makeAny( fRatio );
2178         rPropVal.Handle = -1;
2179         rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2180         pValues[ aValues.getLength() - 1 ] = rPropVal;
2181     }
2182     // <--
2183 
2184     return aValues;
2185 }
2186 
2187 void SwAccessibleParagraph::_getRunAttributesImpl(
2188         const sal_Int32 nIndex,
2189         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
2190         tAccParaPropValMap& rRunAttrSeq )
2191 {
2192     // create PaM for character at position <nIndex>
2193     SwPaM* pPaM( 0 );
2194     {
2195         const SwTxtNode* pTxtNode( GetTxtNode() );
2196         SwPosition* pStartPos = new SwPosition( *pTxtNode );
2197         pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) );
2198         SwPosition* pEndPos = new SwPosition( *pTxtNode );
2199         pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) );
2200 
2201         pPaM = new SwPaM( *pStartPos, *pEndPos );
2202 
2203         delete pStartPos;
2204         delete pEndPos;
2205     }
2206 
2207     // retrieve character attributes for the created PaM <pPaM>
2208     SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(),
2209                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
2210                      0 );
2211     // --> OD 2007-11-12 #i82637#
2212     // From the perspective of the a11y API the character attributes, which
2213     // are set at the automatic paragraph style of the paragraph are treated
2214     // as run attributes.
2215 //    SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True );
2216     // get character attributes from automatic paragraph style and merge these into <aSet>
2217     {
2218         const SwTxtNode* pTxtNode( GetTxtNode() );
2219         if ( pTxtNode->HasSwAttrSet() )
2220         {
2221             SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(),
2222                                                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
2223                                                      0 );
2224             aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False );
2225             aSet.Put( aAutomaticParaStyleCharAttrs );
2226         }
2227     }
2228     // get character attributes at <pPaM> and merge these into <aSet>
2229     {
2230         SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(),
2231                                     RES_CHRATR_BEGIN, RES_CHRATR_END -1,
2232                                     0 );
2233         SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True);
2234         aSet.Put( aCharAttrsAtPaM );
2235     }
2236     // <--
2237 
2238     // build-up sequence containing the run attributes <rRunAttrSeq>
2239     {
2240         tAccParaPropValMap aRunAttrSeq;
2241         {
2242             // --> OD 2007-11-12 #i82637#
2243             tAccParaPropValMap aDefAttrSeq;
2244             uno::Sequence< ::rtl::OUString > aDummy;
2245             _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true );
2246             // <--
2247 
2248             const SfxItemPropertyMap* pPropMap =
2249                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
2250             PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
2251             PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
2252             while ( aPropIt != aPropertyEntries.end() )
2253             {
2254                 const SfxPoolItem* pItem( 0 );
2255                 // --> OD 2007-11-12 #i82637#
2256                 // Found character attributes, whose value equals the value of
2257                 // the corresponding default character attributes, are excluded.
2258                 if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET )
2259                 {
2260                     uno::Any aVal;
2261                     pItem->QueryValue( aVal, aPropIt->nMemberId );
2262 
2263                     PropertyValue rPropVal;
2264                     rPropVal.Name = aPropIt->sName;
2265                     rPropVal.Value = aVal;
2266                     rPropVal.Handle = -1;
2267                     rPropVal.State = PropertyState_DIRECT_VALUE;
2268 
2269                     tAccParaPropValMap::const_iterator aDefIter =
2270                                             aDefAttrSeq.find( rPropVal.Name );
2271                     if ( aDefIter == aDefAttrSeq.end() ||
2272                          rPropVal.Value != aDefIter->second.Value )
2273                     {
2274                         aRunAttrSeq[rPropVal.Name] = rPropVal;
2275                     }
2276                 }
2277 
2278                 ++aPropIt;
2279             }
2280         }
2281 
2282         if ( aRequestedAttributes.getLength() == 0 )
2283         {
2284             rRunAttrSeq = aRunAttrSeq;
2285         }
2286         else
2287         {
2288             const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
2289             const sal_Int32 nLength = aRequestedAttributes.getLength();
2290             for( sal_Int32 i = 0; i < nLength; ++i )
2291             {
2292                 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
2293                 if ( aIter != aRunAttrSeq.end() )
2294                 {
2295                     rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
2296                 }
2297             }
2298         }
2299     }
2300 
2301     delete pPaM;
2302 }
2303 
2304 uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
2305         sal_Int32 nIndex,
2306         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
2307         throw ( lang::IndexOutOfBoundsException,
2308                 uno::RuntimeException )
2309 {
2310     vos::OGuard aGuard(Application::GetSolarMutex());
2311     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2312 
2313     {
2314         const ::rtl::OUString& rText = GetString();
2315         if ( !IsValidChar( nIndex, rText.getLength() ) )
2316         {
2317             throw lang::IndexOutOfBoundsException();
2318         }
2319     }
2320 
2321     tAccParaPropValMap aRunAttrSeq;
2322     _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
2323 
2324     uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() );
2325     PropertyValue* pValues = aValues.getArray();
2326     sal_Int32 i = 0;
2327     for ( tAccParaPropValMap::const_iterator aIter  = aRunAttrSeq.begin();
2328           aIter != aRunAttrSeq.end();
2329           ++aIter )
2330     {
2331         pValues[i] = aIter->second;
2332         ++i;
2333     }
2334 
2335     return aValues;
2336 }
2337 // <--
2338 void SwAccessibleParagraph::_getSupplementalAttributesImpl(
2339         const sal_Int32,
2340         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
2341         tAccParaPropValMap& rSupplementalAttrSeq )
2342 {
2343 	const SwTxtNode* pTxtNode( GetTxtNode() );
2344 	::boost::scoped_ptr<SfxItemSet> pSet;
2345 	pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
2346 		RES_PARATR_ADJUST, RES_PARATR_ADJUST,
2347 		RES_PARATR_TABSTOP, RES_PARATR_TABSTOP,
2348 		RES_PARATR_LINESPACING, RES_PARATR_LINESPACING,
2349 		RES_UL_SPACE, RES_UL_SPACE,
2350 		RES_LR_SPACE, RES_LR_SPACE,
2351 		RES_PARATR_NUMRULE, RES_PARATR_NUMRULE,
2352 		RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
2353 		0 ) );
2354 
2355 	if ( pTxtNode->HasBullet() || pTxtNode->HasNumber() )
2356 	{
2357 		pSet->Put( pTxtNode->GetAttr(RES_PARATR_LIST_LEVEL, RES_PARATR_LIST_LEVEL) );
2358 	}
2359 	pSet->Put( pTxtNode->SwCntntNode::GetAttr(RES_UL_SPACE) );
2360 	pSet->Put( pTxtNode->SwCntntNode::GetAttr(RES_LR_SPACE) );
2361 	pSet->Put( pTxtNode->SwCntntNode::GetAttr(RES_PARATR_ADJUST) );
2362 
2363 	tAccParaPropValMap aSupplementalAttrSeq;
2364     {
2365 //        const SfxItemPropertySet& rPropSet =
2366 //                    aSwMapProvider.GetPropertyMap( PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE );
2367 //        const SfxItemPropertyMap* pPropMap( rPropSet.getPropertyMap() );
2368         const SfxItemPropertyMapEntry* pPropMap(
2369                 aSwMapProvider.GetPropertyMapEntries( PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE ) );
2370         while ( pPropMap->pName )
2371         {
2372             const SfxPoolItem* pItem = pSet->GetItem( pPropMap->nWID );
2373             if ( pItem )
2374             {
2375                 uno::Any aVal;
2376                 pItem->QueryValue( aVal, pPropMap->nMemberId );
2377 
2378                 PropertyValue rPropVal;
2379                 rPropVal.Name = OUString::createFromAscii( pPropMap->pName );
2380                 rPropVal.Value = aVal;
2381                 rPropVal.Handle = -1;
2382                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2383 
2384                 aSupplementalAttrSeq[rPropVal.Name] = rPropVal;
2385             }
2386 
2387             ++pPropMap;
2388         }
2389 	}
2390 
2391 	const OUString* pSupplementalAttrs = aRequestedAttributes.getConstArray();
2392 	const sal_Int32 nSupplementalLength = aRequestedAttributes.getLength();
2393 
2394 	for( sal_Int32 index = 0; index < nSupplementalLength; ++index )
2395 	{
2396 		tAccParaPropValMap::const_iterator const aIter = aSupplementalAttrSeq.find( pSupplementalAttrs[index] );
2397 		if ( aIter != aSupplementalAttrSeq.end() )
2398 		{
2399 			rSupplementalAttrSeq[ aIter->first ] = aIter->second;
2400 		}
2401 	}
2402 }
2403 
2404 void SwAccessibleParagraph::_correctValues( const sal_Int32 nIndex,
2405 										   uno::Sequence< PropertyValue >& rValues)
2406 {
2407 	PropertyValue ChangeAttr, ChangeAttrColor;
2408 
2409 	const SwRedline* pRedline = GetRedlineAtIndex( nIndex );
2410 	if ( pRedline )
2411 	{
2412 
2413 		const SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig();
2414 		AuthorCharAttr aChangeAttr;
2415 		if ( pOpt )
2416 		{
2417 			switch( pRedline->GetType())
2418 			{
2419 			case nsRedlineType_t::REDLINE_INSERT:
2420 				aChangeAttr = pOpt->GetInsertAuthorAttr();
2421 				break;
2422 			case nsRedlineType_t::REDLINE_DELETE:
2423 				aChangeAttr = pOpt->GetDeletedAuthorAttr();
2424 				break;
2425 			case nsRedlineType_t::REDLINE_FORMAT:
2426 				aChangeAttr = pOpt->GetFormatAuthorAttr();
2427 				break;
2428 			}
2429 		}
2430 		switch( aChangeAttr.nItemId )
2431 		{
2432 		case SID_ATTR_CHAR_WEIGHT:
2433 			ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_WEIGHT).pName );
2434 			ChangeAttr.Value <<= awt::FontWeight::BOLD;
2435 			break;
2436 		case SID_ATTR_CHAR_POSTURE:
2437 			ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_POSTURE).pName );
2438 			ChangeAttr.Value <<= awt::FontSlant_ITALIC; //char posture
2439 			break;
2440 		case SID_ATTR_CHAR_STRIKEOUT:
2441 			ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_STRIKEOUT).pName );
2442 			ChangeAttr.Value <<= awt::FontStrikeout::SINGLE; //char strikeout
2443 			break;
2444 		case SID_ATTR_CHAR_UNDERLINE:
2445 			ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_UNDERLINE).pName );
2446 			ChangeAttr.Value <<= aChangeAttr.nAttr; //underline line
2447 			break;
2448 		}
2449 		if( aChangeAttr.nColor != COL_NONE )
2450 		{
2451 			if( aChangeAttr.nItemId == SID_ATTR_BRUSH )
2452 			{
2453 				ChangeAttrColor.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_BACK_COLOR).pName );
2454 				if( aChangeAttr.nColor == COL_TRANSPARENT )//char backcolor
2455 					ChangeAttrColor.Value <<= COL_BLUE;
2456 				else
2457 					ChangeAttrColor.Value <<= aChangeAttr.nColor;
2458 			}
2459 			else
2460 			{
2461 				ChangeAttrColor.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_COLOR ).pName );
2462 				if( aChangeAttr.nColor == COL_TRANSPARENT )//char color
2463 					ChangeAttrColor.Value <<= COL_BLUE;
2464 				else
2465 					ChangeAttrColor.Value <<= aChangeAttr.nColor;
2466 			}
2467 		}
2468 	}
2469 
2470 	PropertyValue* pValues = rValues.getArray();
2471 
2472 	const SwTxtNode* pTxtNode( GetTxtNode() );
2473 
2474 	sal_Int32 nValues = rValues.getLength();
2475 	for (sal_Int32 i = 0;  i < nValues;  ++i)
2476 	{
2477 		PropertyValue& rValue = pValues[i];
2478 
2479 		if (rValue.Name.compareTo( ChangeAttr.Name )==0)
2480 		{
2481 			rValue.Value = ChangeAttr.Value;
2482 			continue;
2483 		}
2484 
2485 		if (rValue.Name.compareTo( ChangeAttrColor.Name )==0)
2486 		{
2487 			rValue.Value = ChangeAttr.Value;
2488 			continue;
2489 		}
2490 
2491 		//back color
2492 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_BACK_COLOR ).pName ) )==0)
2493 		{
2494 			uno::Any &anyChar = rValue.Value;
2495 			sal_uInt32 crBack = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
2496 			if (COL_AUTO == crBack)
2497 			{
2498                 uno::Reference<XAccessibleComponent> xComponent(this);
2499 				if (xComponent.is())
2500 				{
2501 					crBack = (sal_uInt32)xComponent->getBackground();
2502 				}
2503 				rValue.Value <<= crBack;
2504 			}
2505 			continue;
2506 		}
2507 
2508 		//char color
2509 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_COLOR ).pName ) )==0)
2510 		{
2511 			if( GetPortionData().IsInGrayPortion( nIndex ) )
2512 				 rValue.Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
2513 			uno::Any &anyChar = rValue.Value;
2514 			sal_uInt32 crChar = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
2515 
2516 			if( COL_AUTO == crChar )
2517 			{
2518                 uno::Reference<XAccessibleComponent> xComponent(this);
2519 				if (xComponent.is())
2520 				{
2521 					Color cr(xComponent->getBackground());
2522 					crChar = cr.IsDark() ? COL_WHITE : COL_BLACK;
2523 					rValue.Value <<= crChar;
2524 				}
2525 			}
2526 			continue;
2527 		}
2528 
2529 		// UnderLine
2530 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_UNDERLINE ).pName ) )==0)
2531 		{
2532 			//misspelled word
2533 			SwCrsrShell* pCrsrShell = GetCrsrShell();
2534 			if( pCrsrShell != NULL && pCrsrShell->GetViewOptions() && pCrsrShell->GetViewOptions()->IsOnlineSpell())
2535 			{
2536 				const SwWrongList* pWrongList = pTxtNode->GetWrong();
2537 				if( NULL != pWrongList )
2538 				{
2539 					xub_StrLen nBegin = nIndex;
2540 					xub_StrLen nLen = 1;
2541 					if(	pWrongList->InWrongWord(nBegin,nLen) && !pTxtNode->IsSymbol(nBegin) )
2542 					{
2543 						rValue.Value <<= (sal_uInt16)UNDERLINE_WAVE;
2544 					}
2545 				}
2546 			}
2547 			continue;
2548 		}
2549 
2550 		// UnderLineColor
2551 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_UNDERLINE_COLOR ).pName ) )==0)
2552 		{
2553 			//misspelled word
2554 			SwCrsrShell* pCrsrShell = GetCrsrShell();
2555 			if( pCrsrShell != NULL && pCrsrShell->GetViewOptions() && pCrsrShell->GetViewOptions()->IsOnlineSpell())
2556 			{
2557 				const SwWrongList* pWrongList = pTxtNode->GetWrong();
2558 				if( NULL != pWrongList )
2559 				{
2560 					xub_StrLen nBegin = nIndex;
2561 					xub_StrLen nLen = 1;
2562 					if(	pWrongList->InWrongWord(nBegin,nLen) && !pTxtNode->IsSymbol(nBegin) )
2563 					{
2564 						rValue.Value <<= (sal_Int32)0x00ff0000;
2565 						continue;
2566 					}
2567 				}
2568 			}
2569 
2570 			uno::Any &anyChar = rValue.Value;
2571 			sal_uInt32 crUnderline = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
2572 			if ( COL_AUTO == crUnderline )
2573 			{
2574                 uno::Reference<XAccessibleComponent> xComponent(this);
2575 				if (xComponent.is())
2576 				{
2577 					Color cr(xComponent->getBackground());
2578 					crUnderline = cr.IsDark() ? COL_WHITE : COL_BLACK;
2579 					rValue.Value <<= crUnderline;
2580 				}
2581 			}
2582 
2583 			continue;
2584 		}
2585 
2586 		//tab stop
2587 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_TABSTOPS ).pName ) )==0)
2588 		{
2589 			com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > tabs = GetCurrentTabStop( nIndex );
2590 			if( !tabs.hasElements() )
2591 			{
2592 				tabs.realloc(1);
2593 				::com::sun::star::style::TabStop ts;
2594 				com::sun::star::awt::Rectangle rc0 = getCharacterBounds(0);
2595 				com::sun::star::awt::Rectangle rc1 = getCharacterBounds(nIndex);
2596 				if( rc1.X - rc0.X >= 48 )
2597 					ts.Position = (rc1.X - rc0.X) - (rc1.X - rc0.X - 48)% 47 + 47;
2598 				else
2599 					ts.Position = 48;
2600 				ts.DecimalChar = ' ';
2601 				ts.FillChar = ' ';
2602 				ts.Alignment = ::com::sun::star::style::TabAlign_LEFT;
2603 				tabs[0] = ts;
2604 			}
2605 			rValue.Value <<= tabs;
2606 			continue;
2607 		}
2608 
2609 		//number bullet
2610 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_NUMBERING_RULES ).pName ) )==0)
2611 		{
2612 			if ( pTxtNode->HasBullet() || pTxtNode->HasNumber() )
2613 			{
2614                 uno::Any aVal;
2615 				SwNumRule* pNumRule = pTxtNode->GetNumRule();
2616 				if (pNumRule)
2617 				{
2618                     uno::Reference< container::XIndexReplace >  xNum = new SwXNumberingRules(*pNumRule);
2619                     aVal.setValue(&xNum, ::getCppuType((const uno::Reference< container::XIndexReplace >*)0));
2620 				}
2621 				rValue.Value <<= aVal;
2622 			}
2623 			continue;
2624 		}
2625 
2626 		//footnote & endnote
2627 		if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_ESCAPEMENT ).pName ) )==0)
2628 		{
2629 			if ( GetPortionData().IsIndexInFootnode(nIndex) )
2630 			{
2631 				const OUString sEscapmentName = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_ESCAPEMENT ).pName );
2632 				rValue.Value <<= (sal_Int32)101;
2633 			}
2634 			continue;
2635 		}
2636 	}
2637 }
2638 
2639 awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
2640     sal_Int32 nIndex )
2641     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2642 {
2643 	vos::OGuard aGuard(Application::GetSolarMutex());
2644 
2645 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2646 
2647 
2648     /*  #i12332# The position after the string needs special treatment.
2649         IsValidChar -> IsValidPosition
2650     */
2651     if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
2652         throw lang::IndexOutOfBoundsException();
2653 
2654     /*  #i12332#  */
2655     sal_Bool bBehindText = sal_False;
2656     if ( nIndex == GetString().getLength() )
2657         bBehindText = sal_True;
2658 
2659     // get model position & prepare GetCharRect() arguments
2660     SwCrsrMoveState aMoveState;
2661     aMoveState.bRealHeight = sal_True;
2662     aMoveState.bRealWidth = sal_True;
2663     SwSpecialPos aSpecialPos;
2664     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2665 
2666     sal_uInt16 nPos = 0;
2667 
2668     /*  #i12332# FillSpecialPos does not accept nIndex ==
2669          GetString().getLength(). In that case nPos is set to the
2670          length of the string in the core. This way GetCharRect
2671          returns the rectangle for a cursor at the end of the
2672          paragraph. */
2673     if (bBehindText)
2674     {
2675         nPos = pNode->GetTxt().Len();
2676     }
2677     else
2678         nPos = GetPortionData().FillSpecialPos
2679             (nIndex, aSpecialPos, aMoveState.pSpecialPos );
2680 
2681     // call GetCharRect
2682     SwRect aCoreRect;
2683     SwIndex aIndex( pNode, nPos );
2684     SwPosition aPosition( *pNode, aIndex );
2685     GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
2686 
2687     // translate core coordinates into accessibility coordinates
2688 	Window *pWin = GetWindow();
2689 	CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2690 
2691 	Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
2692     SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2693 
2694 	Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
2695 	aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
2696 
2697     // convert into AWT Rectangle
2698     return awt::Rectangle(
2699         aScreenRect.Left(), aScreenRect.Top(),
2700         aScreenRect.GetWidth(), aScreenRect.GetHeight() );
2701 }
2702 
2703 sal_Int32 SwAccessibleParagraph::getCharacterCount()
2704     throw (uno::RuntimeException)
2705 {
2706 	vos::OGuard aGuard(Application::GetSolarMutex());
2707 
2708 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2709 
2710     return GetString().getLength();
2711 }
2712 
2713 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
2714     throw (uno::RuntimeException)
2715 {
2716 	vos::OGuard aGuard(Application::GetSolarMutex());
2717 
2718 
2719 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2720 
2721     // construct SwPosition (where GetCrsrOfst() will put the result into)
2722     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2723     SwIndex aIndex( pNode, 0);
2724     SwPosition aPos( *pNode, aIndex );
2725 
2726     // construct Point (translate into layout coordinates)
2727 	Window *pWin = GetWindow();
2728 	CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2729     Point aPoint( rPoint.X, rPoint.Y );
2730     SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root
2731 	Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
2732 	aPoint.X() += aPixPos.X();
2733 	aPoint.Y() += aPixPos.Y();
2734     MapMode aMapMode = pWin->GetMapMode();
2735 	Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
2736 	if( !aLogBounds.IsInside( aCorePoint ) )
2737     {
2738         /* #i12332# rPoint is may also be in rectangle returned by
2739             getCharacterBounds(getCharacterCount() */
2740 
2741         awt::Rectangle aRectEndPos =
2742             getCharacterBounds(getCharacterCount());
2743 
2744         if (rPoint.X - aRectEndPos.X >= 0 &&
2745             rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
2746             rPoint.Y - aRectEndPos.Y >= 0 &&
2747             rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
2748             return getCharacterCount();
2749 
2750 		return -1;
2751     }
2752 
2753     // ask core for position
2754     DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
2755     DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
2756     const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2757     SwCrsrMoveState aMoveState;
2758     aMoveState.bPosMatchesBounds = sal_True;
2759     sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState );
2760 
2761     SwIndex aCntntIdx = aPos.nContent;
2762     const xub_StrLen nIndex = aCntntIdx.GetIndex();
2763     if ( nIndex > 0 )
2764     {
2765         SwRect aResultRect;
2766         pFrm->GetCharRect( aResultRect, aPos );
2767         bool bVert = pFrm->IsVertical();
2768         bool bR2L = pFrm->IsRightToLeft();
2769 
2770         if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) ||
2771              ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) ||
2772              ( bR2L  && aResultRect.Right()   < aCorePoint.X()) )
2773         {
2774             SwIndex aIdxPrev( pNode, nIndex - 1);
2775             SwPosition aPosPrev( *pNode, aIdxPrev );
2776             SwRect aResultRectPrev;
2777             pFrm->GetCharRect( aResultRectPrev, aPosPrev );
2778             if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ||
2779                  ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) ||
2780                  (  bR2L && aResultRectPrev.Right()   > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) )
2781                 aPos = aPosPrev;
2782         }
2783     }
2784 
2785     return bSuccess ?
2786         GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() )
2787         : -1L;
2788 }
2789 
2790 ::rtl::OUString SwAccessibleParagraph::getSelectedText()
2791     throw (uno::RuntimeException)
2792 {
2793     vos::OGuard aGuard(Application::GetSolarMutex());
2794 
2795 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2796 
2797     sal_Int32 nStart, nEnd;
2798     sal_Bool bSelected = GetSelection( nStart, nEnd );
2799     return bSelected
2800            ? GetString().copy( nStart, nEnd - nStart )
2801            : ::rtl::OUString();
2802 }
2803 
2804 sal_Int32 SwAccessibleParagraph::getSelectionStart()
2805     throw (uno::RuntimeException)
2806 {
2807 	vos::OGuard aGuard(Application::GetSolarMutex());
2808 
2809 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2810 
2811     sal_Int32 nStart, nEnd;
2812     GetSelection( nStart, nEnd );
2813     return nStart;
2814 }
2815 
2816 sal_Int32 SwAccessibleParagraph::getSelectionEnd()
2817     throw (uno::RuntimeException)
2818 {
2819 	vos::OGuard aGuard(Application::GetSolarMutex());
2820 
2821 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2822 
2823     sal_Int32 nStart, nEnd;
2824     GetSelection( nStart, nEnd );
2825     return nEnd;
2826 }
2827 
2828 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2829     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2830 {
2831 	vos::OGuard aGuard(Application::GetSolarMutex());
2832 
2833 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2834 
2835     // parameter checking
2836     sal_Int32 nLength = GetString().getLength();
2837     if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
2838     {
2839         throw lang::IndexOutOfBoundsException();
2840     }
2841 
2842     sal_Bool bRet = sal_False;
2843 
2844     // get cursor shell
2845     SwCrsrShell* pCrsrShell = GetCrsrShell();
2846     if( pCrsrShell != NULL )
2847     {
2848         // create pam for selection
2849         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2850         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex));
2851         SwPosition aStartPos( *pNode, aIndex );
2852         SwPaM aPaM( aStartPos );
2853         aPaM.SetMark();
2854         aPaM.GetPoint()->nContent =
2855             GetPortionData().GetModelPosition(nEndIndex);
2856 
2857         // set PaM at cursor shell
2858         bRet = Select( aPaM );
2859     }
2860 
2861     return bRet;
2862 }
2863 
2864 ::rtl::OUString SwAccessibleParagraph::getText()
2865     throw (uno::RuntimeException)
2866 {
2867 	vos::OGuard aGuard(Application::GetSolarMutex());
2868 
2869 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2870 
2871     return GetString();
2872 }
2873 
2874 ::rtl::OUString SwAccessibleParagraph::getTextRange(
2875     sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2876     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2877 {
2878 	vos::OGuard aGuard(Application::GetSolarMutex());
2879 
2880 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2881 
2882     ::rtl::OUString sText( GetString() );
2883 
2884     if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
2885     {
2886         OrderRange( nStartIndex, nEndIndex );
2887         return sText.copy(nStartIndex, nEndIndex-nStartIndex );
2888     }
2889     else
2890         throw lang::IndexOutOfBoundsException();
2891 }
2892 
2893 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
2894 {
2895 	vos::OGuard aGuard(Application::GetSolarMutex());
2896 
2897 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2898 
2899     /*accessibility::*/TextSegment aResult;
2900     aResult.SegmentStart = -1;
2901     aResult.SegmentEnd = -1;
2902 
2903     const ::rtl::OUString rText = GetString();
2904     // implement the silly specification that first position after
2905     // text must return an empty string, rather than throwing an
2906     // IndexOutOfBoundsException, except for LINE, where the last
2907 	// line is returned
2908     if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
2909 		return aResult;
2910 
2911     // with error checking
2912     i18n::Boundary aBound;
2913     sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2914 
2915     DBG_ASSERT( aBound.startPos >= 0,               "illegal boundary" );
2916     DBG_ASSERT( aBound.startPos <= aBound.endPos,   "illegal boundary" );
2917 
2918     // return word (if present)
2919     if ( bWord )
2920     {
2921     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2922     	aResult.SegmentStart = aBound.startPos;
2923     	aResult.SegmentEnd = aBound.endPos;
2924     }
2925 
2926     return aResult;
2927 }
2928 
2929 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
2930 {
2931 	vos::OGuard aGuard(Application::GetSolarMutex());
2932 
2933 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2934 
2935     const ::rtl::OUString rText = GetString();
2936 
2937     /*accessibility::*/TextSegment aResult;
2938     aResult.SegmentStart = -1;
2939     aResult.SegmentEnd = -1;
2940 	//If nIndex = 0, then nobefore text so return -1 directly.
2941     if( nIndex == 0 )
2942         	return aResult;
2943 	//Tab will be return when call WORDTYPE
2944 
2945     // get starting pos
2946     i18n::Boundary aBound;
2947     if (nIndex ==  rText.getLength())
2948         aBound.startPos = aBound.endPos = nIndex;
2949     else
2950     {
2951         sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
2952 
2953         if ( ! bTmp )
2954             aBound.startPos = aBound.endPos = nIndex;
2955     }
2956 
2957     // now skip to previous word
2958 	if (nTextType==2 || nTextType == 3)
2959 	{
2960         i18n::Boundary preBound = aBound;
2961 		while(preBound.startPos==aBound.startPos && nIndex > 0)
2962 		{
2963 			nIndex = min( nIndex, preBound.startPos ) - 1;
2964 			if( nIndex < 0 ) break;
2965 			GetTextBoundary( preBound, rText, nIndex, nTextType );
2966 		}
2967 		//if (nIndex>0)
2968 		if (nIndex>=0)
2969 		//Tab will be return when call WORDTYPE
2970 		{
2971 			aResult.SegmentText = rText.copy( preBound.startPos, preBound.endPos - preBound.startPos );
2972 			aResult.SegmentStart = preBound.startPos;
2973 			aResult.SegmentEnd = preBound.endPos;
2974 		}
2975 	}
2976 	else
2977 	{
2978 		sal_Bool bWord = sal_False;
2979 		while( !bWord )
2980 		{
2981 			nIndex = min( nIndex, aBound.startPos ) - 1;
2982 			if( nIndex >= 0 )
2983 			{
2984 				bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2985 			}
2986 			else
2987 				break;  // exit if beginning of string is reached
2988 		}
2989 
2990 		if (bWord && nIndex<rText.getLength())
2991 		{
2992 			aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2993 			aResult.SegmentStart = aBound.startPos;
2994 			aResult.SegmentEnd = aBound.endPos;
2995 		}
2996 	}
2997     return aResult;
2998 }
2999 
3000 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
3001 {
3002 	vos::OGuard aGuard(Application::GetSolarMutex());
3003 
3004 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3005 
3006     /*accessibility::*/TextSegment aResult;
3007     aResult.SegmentStart = -1;
3008     aResult.SegmentEnd = -1;
3009     const ::rtl::OUString rText = GetString();
3010 
3011     // implement the silly specification that first position after
3012     // text must return an empty string, rather than throwing an
3013     // IndexOutOfBoundsException
3014     if( nIndex == rText.getLength() )
3015         return aResult;
3016 
3017 
3018     // get first word, then skip to next word
3019     i18n::Boundary aBound;
3020     GetTextBoundary( aBound, rText, nIndex, nTextType );
3021     sal_Bool bWord = sal_False;
3022     while( !bWord )
3023     {
3024         nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
3025         if( nIndex < rText.getLength() )
3026             bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
3027         else
3028             break;  // exit if end of string is reached
3029     }
3030 
3031     if ( bWord )
3032     {
3033     	aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
3034     	aResult.SegmentStart = aBound.startPos;
3035     	aResult.SegmentEnd = aBound.endPos;
3036     }
3037 
3038 /*
3039         sal_Bool bWord = sal_False;
3040     bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
3041 
3042         if (nTextType==2)
3043         {
3044                 Boundary nexBound=aBound;
3045 
3046 		// real current word
3047 		if( nIndex <= aBound.endPos && nIndex >= aBound.startPos )
3048 		{
3049 			while(nexBound.endPos==aBound.endPos&&nIndex<rText.getLength())
3050 			{
3051 				// nIndex = max( (sal_Int32)(nIndex), nexBound.endPos) + 1;
3052 				nIndex = max( (sal_Int32)(nIndex), nexBound.endPos) ;
3053 				const sal_Unicode* pStr = rText.getStr();
3054 				if (pStr)
3055 				{
3056 					if( pStr[nIndex] == sal_Unicode(' ') )
3057 						nIndex++;
3058 				}
3059 				if( nIndex < rText.getLength() )
3060 				{
3061 					bWord = GetTextBoundary( nexBound, rText, nIndex, nTextType );
3062 				}
3063 			}
3064 		}
3065 
3066 		if (bWord && nIndex<rText.getLength())
3067 		{
3068 			aResult.SegmentText = rText.copy( nexBound.startPos, nexBound.endPos - nexBound.startPos );
3069 			aResult.SegmentStart = nexBound.startPos;
3070 			aResult.SegmentEnd = nexBound.endPos;
3071 		}
3072 
3073 	}
3074 	else
3075 	{
3076 		bWord = sal_False;
3077 		while( !bWord )
3078 		{
3079 			nIndex = max( (sal_Int32)(nIndex+1), aBound.endPos );
3080 			if( nIndex < rText.getLength() )
3081 			{
3082 				bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
3083 			}
3084 			else
3085 				break;  // exit if end of string is reached
3086 		}
3087 		if (bWord && nIndex<rText.getLength())
3088 		{
3089 			aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
3090 			aResult.SegmentStart = aBound.startPos;
3091 			aResult.SegmentEnd = aBound.endPos;
3092 		}
3093 	}
3094 */
3095     return aResult;
3096 }
3097 
3098 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
3099     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3100 {
3101 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3102 	vos::OGuard aGuard(Application::GetSolarMutex());
3103 
3104     // select and copy (through dispatch mechanism)
3105     setSelection( nStartIndex, nEndIndex );
3106     ExecuteAtViewShell( SID_COPY );
3107     return sal_True;
3108 }
3109 
3110 
3111 //
3112 //=====  XAccesibleEditableText  ==========================================
3113 //
3114 
3115 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
3116     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3117 {
3118 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
3119 	vos::OGuard aGuard(Application::GetSolarMutex());
3120 
3121 	if( !IsEditableState() )
3122 		return sal_False;
3123 
3124     // select and cut (through dispatch mechanism)
3125     setSelection( nStartIndex, nEndIndex );
3126     ExecuteAtViewShell( SID_CUT );
3127     return sal_True;
3128 }
3129 
3130 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
3131     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3132 {
3133 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
3134 	vos::OGuard aGuard(Application::GetSolarMutex());
3135 
3136 	if( !IsEditableState() )
3137 		return sal_False;
3138 
3139     // select and paste (through dispatch mechanism)
3140     setSelection( nIndex, nIndex );
3141     ExecuteAtViewShell( SID_PASTE );
3142     return sal_True;
3143 }
3144 
3145 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
3146     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3147 {
3148     return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() );
3149 }
3150 
3151 sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex )
3152     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3153 {
3154     return replaceText( nIndex, nIndex, sText );
3155 }
3156 
3157 sal_Bool SwAccessibleParagraph::replaceText(
3158     sal_Int32 nStartIndex, sal_Int32 nEndIndex,
3159     const ::rtl::OUString& sReplacement )
3160     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3161 {
3162 	vos::OGuard aGuard(Application::GetSolarMutex());
3163 
3164 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
3165 
3166     const ::rtl::OUString& rText = GetString();
3167 
3168     if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
3169     {
3170 		if( !IsEditableState() )
3171 			return sal_False;
3172 
3173         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
3174 
3175         // translate positions
3176         sal_uInt16 nStart, nEnd;
3177         sal_Bool bSuccess = GetPortionData().GetEditableRange(
3178                                         nStartIndex, nEndIndex, nStart, nEnd );
3179 
3180         // edit only if the range is editable
3181         if( bSuccess )
3182         {
3183             // create SwPosition for nStartIndex
3184             SwIndex aIndex( pNode, nStart );
3185             SwPosition aStartPos( *pNode, aIndex );
3186 
3187             // create SwPosition for nEndIndex
3188             SwPosition aEndPos( aStartPos );
3189             aEndPos.nContent = nEnd;
3190 
3191             // now create XTextRange as helper and set string
3192             const uno::Reference<text::XTextRange> xRange(
3193                 SwXTextRange::CreateXTextRange(
3194                     *pNode->GetDoc(), aStartPos, &aEndPos));
3195             xRange->setString(sReplacement);
3196 
3197             // delete portion data
3198             ClearPortionData();
3199         }
3200 
3201         return bSuccess;
3202     }
3203     else
3204         throw lang::IndexOutOfBoundsException();
3205 }
3206 
3207 
3208 sal_Bool SwAccessibleParagraph::setAttributes(
3209     sal_Int32 nStartIndex,
3210     sal_Int32 nEndIndex,
3211     const uno::Sequence<PropertyValue>& rAttributeSet )
3212     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3213 {
3214 	vos::OGuard aGuard(Application::GetSolarMutex());
3215 	CHECK_FOR_DEFUNC( XAccessibleEditableText );
3216 
3217     const ::rtl::OUString& rText = GetString();
3218 
3219     if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
3220         throw lang::IndexOutOfBoundsException();
3221 
3222 	if( !IsEditableState() )
3223 		return sal_False;
3224 
3225 
3226     // create a (dummy) text portion for the sole purpose of calling
3227     // setPropertyValue on it
3228     uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
3229                                                               nEndIndex );
3230 
3231     // build sorted index array
3232     sal_Int32 nLength = rAttributeSet.getLength();
3233     const PropertyValue* pPairs = rAttributeSet.getConstArray();
3234     sal_Int32* pIndices = new sal_Int32[nLength];
3235     sal_Int32 i;
3236     for( i = 0; i < nLength; i++ )
3237         pIndices[i] = i;
3238     sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
3239 
3240     // create sorted sequences accoring to index array
3241     uno::Sequence< ::rtl::OUString > aNames( nLength );
3242     ::rtl::OUString* pNames = aNames.getArray();
3243     uno::Sequence< uno::Any > aValues( nLength );
3244     uno::Any* pValues = aValues.getArray();
3245     for( i = 0; i < nLength; i++ )
3246     {
3247         const PropertyValue& rVal = pPairs[pIndices[i]];
3248         pNames[i]  = rVal.Name;
3249         pValues[i] = rVal.Value;
3250     }
3251     delete[] pIndices;
3252 
3253     // now set the values
3254     sal_Bool bRet = sal_True;
3255     try
3256     {
3257         xPortion->setPropertyValues( aNames, aValues );
3258     }
3259     catch( UnknownPropertyException e )
3260     {
3261         // error handling through return code!
3262         bRet = sal_False;
3263     }
3264 
3265     return bRet;
3266 }
3267 
3268 sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText )
3269     throw (uno::RuntimeException)
3270 {
3271     return replaceText(0, GetString().getLength(), sText);
3272 }
3273 
3274 //=====  XAccessibleSelection  ============================================
3275 
3276 void SwAccessibleParagraph::selectAccessibleChild(
3277     sal_Int32 nChildIndex )
3278     throw ( lang::IndexOutOfBoundsException,
3279             uno::RuntimeException )
3280 {
3281 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3282 
3283     aSelectionHelper.selectAccessibleChild(nChildIndex);
3284 }
3285 
3286 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
3287     sal_Int32 nChildIndex )
3288     throw ( lang::IndexOutOfBoundsException,
3289             uno::RuntimeException )
3290 {
3291 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3292 
3293     return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
3294 }
3295 
3296 void SwAccessibleParagraph::clearAccessibleSelection(  )
3297     throw ( uno::RuntimeException )
3298 {
3299 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3300 
3301     aSelectionHelper.clearAccessibleSelection();
3302 }
3303 
3304 void SwAccessibleParagraph::selectAllAccessibleChildren(  )
3305     throw ( uno::RuntimeException )
3306 {
3307 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3308 
3309     aSelectionHelper.selectAllAccessibleChildren();
3310 }
3311 
3312 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount(  )
3313     throw ( uno::RuntimeException )
3314 {
3315 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3316 
3317     return aSelectionHelper.getSelectedAccessibleChildCount();
3318 }
3319 
3320 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
3321     sal_Int32 nSelectedChildIndex )
3322     throw ( lang::IndexOutOfBoundsException,
3323             uno::RuntimeException)
3324 {
3325 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3326 
3327     return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
3328 }
3329 
3330 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
3331 void SwAccessibleParagraph::deselectAccessibleChild(
3332     sal_Int32 nChildIndex )
3333     throw ( lang::IndexOutOfBoundsException,
3334             uno::RuntimeException )
3335 {
3336 	CHECK_FOR_DEFUNC( XAccessibleSelection );
3337 
3338     aSelectionHelper.deselectAccessibleChild( nChildIndex );
3339 }
3340 
3341 //=====  XAccessibleHypertext  ============================================
3342 
3343 class SwHyperlinkIter_Impl
3344 {
3345 	const SwpHints *pHints;
3346 	xub_StrLen nStt;
3347 	xub_StrLen nEnd;
3348 	sal_uInt16 nPos;
3349 
3350 public:
3351 	SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm );
3352 	const SwTxtAttr *next();
3353 	sal_uInt16 getCurrHintPos() const { return nPos-1; }
3354 
3355 	xub_StrLen startIdx() const { return nStt; }
3356 	xub_StrLen endIdx() const { return nEnd; }
3357 };
3358 
3359 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) :
3360 	pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ),
3361 	nStt( pTxtFrm->GetOfst() ),
3362 	nPos( 0 )
3363 {
3364 	const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow();
3365 	nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len();
3366 }
3367 
3368 const SwTxtAttr *SwHyperlinkIter_Impl::next()
3369 {
3370 	const SwTxtAttr *pAttr = 0;
3371 	if( pHints )
3372 	{
3373 		while( !pAttr && nPos < pHints->Count() )
3374 		{
3375 			const SwTxtAttr *pHt = (*pHints)[nPos];
3376 			if( RES_TXTATR_INETFMT == pHt->Which() )
3377 			{
3378 				xub_StrLen nHtStt = *pHt->GetStart();
3379 				xub_StrLen nHtEnd = *pHt->GetAnyEnd();
3380 				if( nHtEnd > nHtStt &&
3381 					( (nHtStt >= nStt && nHtStt < nEnd) ||
3382 					  (nHtEnd > nStt && nHtEnd <= nEnd) ) )
3383 				{
3384 					pAttr = pHt;
3385 				}
3386 			}
3387 			++nPos;
3388 		}
3389 	}
3390 
3391 	return pAttr;
3392 };
3393 
3394 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
3395     throw (uno::RuntimeException)
3396 {
3397 	vos::OGuard aGuard(Application::GetSolarMutex());
3398 
3399 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
3400 
3401 	sal_Int32 nCount = 0;
3402     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
3403 //    if( !IsEditableState() )
3404     // <--
3405 	{
3406 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3407 		SwHyperlinkIter_Impl aIter( pTxtFrm );
3408 		while( aIter.next() )
3409 			nCount++;
3410 	}
3411 
3412 	/* Can't fin the function "GetTOCFirstWordEndIndex" declaration in sym2.0 (Added by yanjun)
3413 	if( GetTOXSortTabBase()  )
3414 	{
3415 		SwTxtNode* pNode = const_cast<SwTxtNode*>(GetTxtNode());
3416 		if(pNode && pNode->GetTOCFirstWordEndIndex() > 0)
3417 			nCount++;
3418 	}
3419 	*/
3420 	return nCount;
3421 }
3422 
3423 uno::Reference< XAccessibleHyperlink > SAL_CALL
3424 	SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
3425     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3426 {
3427 	vos::OGuard aGuard(Application::GetSolarMutex());
3428 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
3429 
3430     uno::Reference< XAccessibleHyperlink > xRet;
3431 
3432     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
3433 //    if( !IsEditableState() )
3434 	const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3435 	SwHyperlinkIter_Impl aHIter( pTxtFrm );
3436 	//SwAccessibleAutoRecognizerHelper_Impl aARHelper( pTxtFrm );
3437 	sal_Int32 nARCount = 0;
3438 	sal_Int32 nARIndex = 0;
3439 	sal_Int32 nTIndex = -1;
3440 	sal_Int32 nTOCEndIndex = -1;
3441 	SwTxtNode* pNode = NULL;
3442 	SwTOXSortTabBase* pTBase = GetTOXSortTabBase();
3443 	if( pTBase )
3444 	{
3445 		pNode = const_cast<SwTxtNode*>(GetTxtNode());
3446 	}
3447 	nTOCEndIndex = -1;
3448 	//if(pNode)
3449 	//	nTOCEndIndex = pNode->GetTOCFirstWordEndIndex();
3450 	SwTxtAttr* pHt = (SwTxtAttr*)(aHIter.next());
3451 	while( (nLinkIndex < getHyperLinkCount()) && nTIndex < nLinkIndex)
3452 	{
3453 		// no candidates, exit
3454 		//if( (!pHt) && (nARIndex >= nARCount) && nTOCEndIndex <= 0)
3455 		//	break;
3456 
3457 		sal_Int32 nHStt = -1;
3458 		sal_Int32 nAStt = -1;
3459 		sal_Bool bH = sal_False;
3460 		sal_Bool bA = sal_False;
3461 
3462 
3463 		if( pHt )
3464 			nHStt = *pHt->GetStart();
3465 		if( nARIndex < nARCount )
3466 		{
3467 			/*
3468 			sal_Int32 nAEnd;
3469 			aARHelper.getPosition( nARIndex, nAStt, nAEnd );
3470 			*/
3471 		}
3472 		sal_Bool bTOC = sal_False;
3473 		// Inside TOC & get the first link
3474 		if( pTBase && nTIndex == -1 )
3475 		{
3476 			nTIndex++;
3477 			bTOC = sal_True;
3478 		}
3479 		else
3480 		{
3481 			if( nHStt >=0 && nAStt >=0 )
3482 			{	// both hyperlink and smart tag available
3483 				nTIndex++;
3484 				if( nHStt <= nAStt )
3485 					bH = sal_True;
3486 				else
3487 					bA = sal_True;
3488 			}
3489 			else if( nHStt >= 0 )
3490 			{	// only hyperlink available
3491 				nTIndex++;
3492 				bH = sal_True;
3493 			}
3494 			else if( nAStt >= 0 )
3495 			{	// only smart tag available
3496 				nTIndex++;
3497 				bA = sal_True;
3498 			}
3499 		}
3500 
3501 		if( nTIndex == nLinkIndex )
3502 		{	// found
3503 			if( bH )
3504 			{	// it's a hyperlink
3505 				if( pHt )
3506 				{
3507 //                    const SwField* pFFld = pHt->GetFld().GetFld();
3508                     {
3509 						if( !pHyperTextData )
3510 							pHyperTextData = new SwAccessibleHyperTextData;
3511 						SwAccessibleHyperTextData::iterator aIter =
3512 							pHyperTextData ->find( pHt );
3513 						if( aIter != pHyperTextData->end() )
3514 						{
3515 							xRet = (*aIter).second;
3516 						}
3517 						if( !xRet.is() )
3518 						{
3519                             {
3520                                 const sal_Int32 nTmpHStt= GetPortionData().GetAccessiblePosition(
3521                                     max( aHIter.startIdx(), *pHt->GetStart() ) );
3522                                 const sal_Int32 nTmpHEnd= GetPortionData().GetAccessiblePosition(
3523                                     min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
3524                                 xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
3525                                     this, nTmpHStt, nTmpHEnd );
3526                             }
3527 							if( aIter != pHyperTextData->end() )
3528 							{
3529 								(*aIter).second = xRet;
3530 							}
3531 							else
3532 							{
3533 								SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
3534 								pHyperTextData->insert( aEntry );
3535 							}
3536 						}
3537 					}
3538 				}
3539 			}
3540 			else if( bTOC )
3541 			{
3542 				//xRet = new SwAccessibleTOCLink( this );
3543 			}
3544 			else if( bA )
3545 			{
3546 				/*
3547 				// it's a smart tag
3548 				if( !pAutoRecognizerData )
3549 					pAutoRecognizerData = new SwAccessibleAutoRecognizerData;
3550 				SwAccessibleAutoRecognizerData::iterator aIter =
3551 					pAutoRecognizerData ->find( nARIndex );
3552 				if( aIter != pAutoRecognizerData->end() )
3553 				{
3554 					xRet = (*aIter).second;
3555 				}
3556 				if( !xRet.is() )
3557 				{
3558 					sal_Int32 nAStt = 0;
3559 					sal_Int32 nAEnd = 0;
3560 					//aARHelper.getPosition( nARIndex, nAStt, nAEnd );
3561 					xRet = new SwAccessibleAutoRecognizer( this, nAStt, nAEnd );
3562 					if( aIter != pAutoRecognizerData->end() )
3563 					{
3564 						(*aIter).second = xRet;
3565 					}
3566 					else
3567 					{
3568 						SwAccessibleAutoRecognizerData::value_type aEntry( nARIndex, xRet );
3569 						pAutoRecognizerData->insert( aEntry );
3570 					}
3571 				}
3572 				*/
3573 			}
3574 			break;
3575 		}
3576 
3577 		// iterate next
3578 		if( bH )
3579 			// iterate next hyperlink
3580 			pHt = (SwTxtAttr*)(aHIter.next());
3581 		else if( bA )
3582 			// iterate next smart tag
3583 			nARIndex++;
3584 		else if(bTOC)
3585 			continue;
3586 		else
3587 			// no candidate, exit
3588 			break;
3589 	}
3590 	/*
3591 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3592 		SwHyperlinkIter_Impl aHIter( pTxtFrm );
3593 		while( nLinkIndex-- )
3594 			aHIter.next();
3595 
3596 		const SwTxtAttr *pHt = aHIter.next();
3597 		if( pHt )
3598 		{
3599 			if( !pHyperTextData )
3600 				pHyperTextData = new SwAccessibleHyperTextData;
3601 			SwAccessibleHyperTextData::iterator aIter =
3602 				pHyperTextData ->find( pHt );
3603 			if( aIter != pHyperTextData->end() )
3604 			{
3605 				xRet = (*aIter).second;
3606 			}
3607 			if( !xRet.is() )
3608 			{
3609 				sal_Int32 nHStt= GetPortionData().GetAccessiblePosition(
3610 								max( aHIter.startIdx(), *pHt->GetStart() ) );
3611 				sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition(
3612 								min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
3613 				xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
3614 												  this, nHStt, nHEnd );
3615 				if( aIter != pHyperTextData->end() )
3616 				{
3617 					(*aIter).second = xRet;
3618 				}
3619 				else
3620 				{
3621 					SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
3622 					pHyperTextData->insert( aEntry );
3623 				}
3624 			}
3625 		}
3626 	}
3627 	*/
3628 	if( !xRet.is() )
3629         throw lang::IndexOutOfBoundsException();
3630 
3631 	return xRet;
3632 }
3633 
3634 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
3635     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3636 {
3637 	vos::OGuard aGuard(Application::GetSolarMutex());
3638 	CHECK_FOR_DEFUNC( XAccessibleHypertext );
3639 
3640     // parameter checking
3641     sal_Int32 nLength = GetString().getLength();
3642     if ( ! IsValidPosition( nCharIndex, nLength ) )
3643     {
3644         throw lang::IndexOutOfBoundsException();
3645     }
3646 
3647 	sal_Int32 nRet = -1;
3648     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
3649 //    if( !IsEditableState() )
3650     // <--
3651 	{
3652 		const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3653 		SwHyperlinkIter_Impl aHIter( pTxtFrm );
3654 
3655 		xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex );
3656 		sal_Int32 nPos = 0;
3657 		const SwTxtAttr *pHt = aHIter.next();
3658 		while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) )
3659 		{
3660 			pHt = aHIter.next();
3661 			nPos++;
3662 		}
3663 
3664 		if( pHt )
3665 			nRet = nPos;
3666 	}
3667 	/* Added by yanjun for acc miagration
3668 	if( nRet == -1 && GetTOXSortTabBase() )
3669 	{
3670 		SwTxtNode* pNode = const_cast<SwTxtNode*>(GetTxtNode());
3671 		if( nCharIndex >= 0 && nCharIndex < pNode->GetTOCFirstWordEndIndex())
3672 			nRet = 0;
3673 	}
3674 	*/
3675 
3676 	if (nRet == -1)
3677 		throw lang::IndexOutOfBoundsException();
3678 	else
3679 		return nRet;
3680 	//return nRet;
3681 }
3682 
3683 // --> OD 2008-05-26 #i71360#
3684 // --> OD 2010-02-22 #i108125# - adjustments for change tracking text markup
3685 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
3686                                         throw (lang::IllegalArgumentException,
3687                                                uno::RuntimeException)
3688 {
3689     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3690     switch ( nTextMarkupType )
3691     {
3692         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3693         case text::TextMarkupType::TRACK_CHANGE_DELETION:
3694         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3695         {
3696             pTextMarkupHelper.reset( new SwTextMarkupHelper(
3697                 GetPortionData(),
3698                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3699         }
3700         break;
3701         default:
3702         {
3703             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
3704         }
3705     }
3706 
3707     return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType );
3708 }
3709 //MSAA Extension Implementation in app  module
3710 sal_Bool SAL_CALL SwAccessibleParagraph::scrollToPosition( const ::com::sun::star::awt::Point&, sal_Bool )
3711 	throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
3712 {
3713 	return sal_False;
3714 }
3715 
3716 sal_Int32 SAL_CALL SwAccessibleParagraph::getSelectedPortionCount(  )
3717 	throw (::com::sun::star::uno::RuntimeException)
3718 {
3719 	sal_Int32 nSeleted = 0;
3720 	SwPaM* pCrsr = GetCursor( true );
3721     if( pCrsr != NULL )
3722     {
3723         // get SwPosition for my node
3724         const SwTxtNode* pNode = GetTxtNode();
3725         sal_uLong nHere = pNode->GetIndex();
3726 
3727         // iterate over ring
3728         SwPaM* pRingStart = pCrsr;
3729         do
3730         {
3731             // ignore, if no mark
3732             if( pCrsr->HasMark() )
3733             {
3734                 // check whether nHere is 'inside' pCrsr
3735                 SwPosition* pStart = pCrsr->Start();
3736                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3737                 SwPosition* pEnd = pCrsr->End();
3738                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3739                 if( ( nHere >= nStartIndex ) &&
3740                     ( nHere <= nEndIndex )      )
3741                 {
3742 					nSeleted++;
3743                 }
3744                 // else: this PaM doesn't point to this paragraph
3745             }
3746             // else: this PaM is collapsed and doesn't select anything
3747 
3748             // next PaM in ring
3749             pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
3750         }
3751         while( pCrsr != pRingStart );
3752     }
3753 	return nSeleted;
3754 
3755 }
3756 
3757 sal_Int32 SAL_CALL SwAccessibleParagraph::getSeletedPositionStart( sal_Int32 nSelectedPortionIndex )
3758 	throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3759 {
3760 	vos::OGuard aGuard(Application::GetSolarMutex());
3761 
3762 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3763 
3764 	sal_Int32 nStart, nEnd;
3765     /*sal_Bool bSelected = */GetSelectionAtIndex(nSelectedPortionIndex, nStart, nEnd );
3766 	return nStart;
3767 }
3768 
3769 sal_Int32 SAL_CALL SwAccessibleParagraph::getSeletedPositionEnd( sal_Int32 nSelectedPortionIndex )
3770 	throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3771 {
3772 	vos::OGuard aGuard(Application::GetSolarMutex());
3773 
3774 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3775 
3776 	sal_Int32 nStart, nEnd;
3777     /*sal_Bool bSelected = */GetSelectionAtIndex(nSelectedPortionIndex, nStart, nEnd );
3778 	return nEnd;
3779 }
3780 
3781 sal_Bool SAL_CALL SwAccessibleParagraph::removeSelection( sal_Int32 selectionIndex )
3782 	throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3783 {
3784 	if(selectionIndex < 0) return sal_False;
3785 
3786     sal_Bool bRet = sal_False;
3787 	sal_Int32 nSelected = selectionIndex;
3788 
3789     // get the selection, and test whether it affects our text node
3790 	SwPaM* pCrsr = GetCursor( true );
3791 //  SwPaM* pFirst = pCrsr;
3792 	SwPaM* pPrev = pCrsr;
3793 
3794     if( pCrsr != NULL )
3795     {
3796         // get SwPosition for my node
3797         const SwTxtNode* pNode = GetTxtNode();
3798         sal_uLong nHere = pNode->GetIndex();
3799 
3800         // iterate over ring
3801         SwPaM* pRingStart = pCrsr;
3802         do
3803         {
3804             // ignore, if no mark
3805             if( pCrsr->HasMark() )
3806             {
3807                 // check whether nHere is 'inside' pCrsr
3808                 SwPosition* pStart = pCrsr->Start();
3809                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3810                 SwPosition* pEnd = pCrsr->End();
3811                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3812                 if( ( nHere >= nStartIndex ) &&
3813                     ( nHere <= nEndIndex )      )
3814                 {
3815 					if( nSelected == 0 )
3816 					{
3817 						pCrsr->MoveTo((Ring*)0);
3818 						delete pCrsr;
3819 						bRet = sal_True;
3820 					}
3821 					else
3822 					{
3823 						nSelected--;
3824 					}
3825 				}
3826 			}
3827             // else: this PaM is collapsed and doesn't select anything
3828 		   pPrev = pCrsr;
3829            pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
3830         }
3831         while( !bRet && (pCrsr != pRingStart) );
3832 	}
3833 	return sal_True;
3834 }
3835 
3836 sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection( sal_Int32, sal_Int32 startOffset, sal_Int32 endOffset)
3837 	throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3838 {
3839 	vos::OGuard aGuard(Application::GetSolarMutex());
3840 
3841 	CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3842 
3843     // parameter checking
3844     sal_Int32 nLength = GetString().getLength();
3845     if ( ! IsValidRange( startOffset, endOffset, nLength ) )
3846     {
3847         throw lang::IndexOutOfBoundsException();
3848     }
3849 
3850 	sal_Int32 nSelectedCount = getSelectedPortionCount();
3851 	for ( sal_Int32 i = nSelectedCount ; i >= 0 ; i--)
3852 	{
3853 		sal_Int32 nStart, nEnd;
3854 		sal_Bool bSelected = GetSelectionAtIndex(i, nStart, nEnd );
3855 		if(bSelected)
3856 		{
3857 			if(nStart <= nEnd )
3858 			{
3859 				if (( startOffset>=nStart && startOffset <=nEnd ) ||     //startOffset in a selection
3860 			   		( endOffset>=nStart && endOffset <=nEnd )     ||  //endOffset in a selection
3861 					( startOffset <= nStart && endOffset >=nEnd)  ||       //start and  end include the old selection
3862 					( startOffset >= nStart && endOffset <=nEnd) )
3863 				{
3864 					removeSelection(i);
3865 				}
3866 
3867 			}
3868 			else
3869 			{
3870 				if (( startOffset>=nEnd && startOffset <=nStart ) ||     //startOffset in a selection
3871 			   		( endOffset>=nEnd && endOffset <=nStart )     || //endOffset in a selection
3872 					( startOffset <= nStart && endOffset >=nEnd)  ||       //start and  end include the old selection
3873 					( startOffset >= nStart && endOffset <=nEnd) )
3874 
3875 				{
3876 					removeSelection(i);
3877 				}
3878 			}
3879 		}
3880 
3881 	}
3882 
3883     sal_Bool bRet = sal_False;
3884 
3885     // get cursor shell
3886     SwCrsrShell* pCrsrShell = GetCrsrShell();
3887     if( pCrsrShell != NULL )
3888     {
3889         // create pam for selection
3890 		pCrsrShell->StartAction();
3891 //        SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
3892         SwPaM* aPaM = pCrsrShell->CreateCrsr();
3893         aPaM->SetMark();
3894 		aPaM->GetPoint()->nContent = GetPortionData().GetModelPosition(startOffset);
3895         aPaM->GetMark()->nContent =  GetPortionData().GetModelPosition(endOffset);
3896 		//pCrsrShell->ShowCrsr();
3897 		pCrsrShell->EndAction();
3898         // set PaM at cursor shell
3899         //bRet = Select( aPaM );
3900     }
3901 
3902     return bRet;
3903 }
3904 
3905 /*accessibility::*/TextSegment SAL_CALL
3906         SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
3907                                               sal_Int32 nTextMarkupType )
3908                                         throw (lang::IndexOutOfBoundsException,
3909                                                lang::IllegalArgumentException,
3910                                                uno::RuntimeException)
3911 {
3912     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3913     switch ( nTextMarkupType )
3914     {
3915         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3916         case text::TextMarkupType::TRACK_CHANGE_DELETION:
3917         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3918         {
3919             pTextMarkupHelper.reset( new SwTextMarkupHelper(
3920                 GetPortionData(),
3921                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3922         }
3923         break;
3924         default:
3925         {
3926             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
3927         }
3928     }
3929 
3930     return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
3931 }
3932 
3933 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
3934         SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
3935                                                      sal_Int32 nTextMarkupType )
3936                                         throw (lang::IndexOutOfBoundsException,
3937                                                lang::IllegalArgumentException,
3938                                                uno::RuntimeException)
3939 {
3940     // parameter checking
3941     const sal_Int32 nLength = GetString().getLength();
3942     if ( ! IsValidPosition( nCharIndex, nLength ) )
3943     {
3944         throw lang::IndexOutOfBoundsException();
3945     }
3946 
3947     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3948     switch ( nTextMarkupType )
3949     {
3950         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3951         case text::TextMarkupType::TRACK_CHANGE_DELETION:
3952         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3953         {
3954             pTextMarkupHelper.reset( new SwTextMarkupHelper(
3955                 GetPortionData(),
3956                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3957         }
3958         break;
3959         default:
3960         {
3961             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
3962         }
3963     }
3964 
3965     return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
3966 }
3967 // <--
3968 
3969 // --> OD 2008-05-29 #i89175#
3970 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
3971                                         throw (lang::IndexOutOfBoundsException,
3972                                                uno::RuntimeException)
3973 {
3974     // parameter checking
3975     const sal_Int32 nLength = GetString().getLength();
3976     if ( ! IsValidPosition( nIndex, nLength ) )
3977     {
3978         throw lang::IndexOutOfBoundsException();
3979     }
3980 
3981     const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
3982     return nLineNo;
3983 }
3984 
3985 /*accessibility::*/TextSegment SAL_CALL
3986         SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
3987                                         throw (lang::IndexOutOfBoundsException,
3988                                                uno::RuntimeException)
3989 {
3990     // parameter checking
3991     if ( nLineNo < 0 ||
3992          nLineNo >= GetPortionData().GetLineCount() )
3993     {
3994         throw lang::IndexOutOfBoundsException();
3995     }
3996 
3997     i18n::Boundary aLineBound;
3998     GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
3999 
4000     /*accessibility::*/TextSegment aTextAtLine;
4001     const ::rtl::OUString rText = GetString();
4002     aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
4003                                           aLineBound.endPos - aLineBound.startPos );
4004     aTextAtLine.SegmentStart = aLineBound.startPos;
4005     aTextAtLine.SegmentEnd = aLineBound.endPos;
4006 
4007     return aTextAtLine;
4008 }
4009 
4010 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
4011                                         throw (uno::RuntimeException)
4012 {
4013     const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
4014 
4015     if ( nLineNoOfCaret >= 0 &&
4016          nLineNoOfCaret < GetPortionData().GetLineCount() )
4017     {
4018         return getTextAtLineNumber( nLineNoOfCaret );
4019     }
4020 
4021     return /*accessibility::*/TextSegment();
4022 }
4023 
4024 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
4025                                         throw (uno::RuntimeException)
4026 {
4027     const sal_Int32 nCaretPos = getCaretPosition();
4028     const sal_Int32 nLength = GetString().getLength();
4029     if ( !IsValidPosition( nCaretPos, nLength ) )
4030     {
4031         return -1;
4032     }
4033 
4034     sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
4035 
4036     // special handling for cursor positioned at end of text line via End key
4037     if ( nCaretPos != 0 )
4038     {
4039         i18n::Boundary aLineBound;
4040         GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
4041         if ( nCaretPos == aLineBound.startPos )
4042         {
4043             SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
4044             if ( pCrsrShell != 0 )
4045             {
4046                 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
4047 
4048                 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect();
4049                 // translate core coordinates into accessibility coordinates
4050                 Window *pWin = GetWindow();
4051                 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
4052 
4053                 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
4054 
4055                 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
4056                 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
4057                 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
4058 
4059                 // convert into AWT Rectangle
4060                 const awt::Rectangle aCursorRect( aScreenRect.Left(),
4061                                                   aScreenRect.Top(),
4062                                                   aScreenRect.GetWidth(),
4063                                                   aScreenRect.GetHeight() );
4064 
4065                 if ( aCharRect.X != aCursorRect.X ||
4066                      aCharRect.Y != aCursorRect.Y )
4067                 {
4068                     --nLineNo;
4069                 }
4070             }
4071         }
4072     }
4073 
4074     return nLineNo;
4075 }
4076 
4077 // --> OD 2010-02-19 #i108125#
4078 void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
4079 {
4080     mpParaChangeTrackInfo->reset();
4081 
4082     CheckRegistration( pOld, pNew );
4083 }
4084 // <--
4085 
4086 sal_Bool SwAccessibleParagraph::GetSelectionAtIndex(
4087     sal_Int32& nIndex, sal_Int32& nStart, sal_Int32& nEnd)
4088 {
4089         if(nIndex < 0) return sal_False;
4090 
4091 
4092     sal_Bool bRet = sal_False;
4093     nStart = -1;
4094     nEnd = -1;
4095 	sal_Int32 nSelected = nIndex;
4096 
4097     // get the selection, and test whether it affects our text node
4098 	SwPaM* pCrsr = GetCursor( true );
4099     if( pCrsr != NULL )
4100     {
4101         // get SwPosition for my node
4102         const SwTxtNode* pNode = GetTxtNode();
4103         sal_uLong nHere = pNode->GetIndex();
4104 
4105         // iterate over ring
4106         SwPaM* pRingStart = pCrsr;
4107         do
4108         {
4109             // ignore, if no mark
4110             if( pCrsr->HasMark() )
4111             {
4112                 // check whether nHere is 'inside' pCrsr
4113                 SwPosition* pStart = pCrsr->Start();
4114                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
4115                 SwPosition* pEnd = pCrsr->End();
4116                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
4117                 if( ( nHere >= nStartIndex ) &&
4118                     ( nHere <= nEndIndex )      )
4119                 {
4120 					if( nSelected == 0 )
4121 					{
4122 						// translate start and end positions
4123 
4124 						// start position
4125 						sal_Int32 nLocalStart = -1;
4126 						if( nHere > nStartIndex )
4127 						{
4128 							// selection starts in previous node:
4129 							// then our local selection starts with the paragraph
4130 							nLocalStart = 0;
4131 						}
4132 						else
4133 						{
4134 							DBG_ASSERT( nHere == nStartIndex,
4135 										"miscalculated index" );
4136 
4137 							// selection starts in this node:
4138 							// then check whether it's before or inside our part of
4139 							// the paragraph, and if so, get the proper position
4140 							sal_uInt16 nCoreStart = pStart->nContent.GetIndex();
4141 							if( nCoreStart <
4142 								GetPortionData().GetFirstValidCorePosition() )
4143 							{
4144 								nLocalStart = 0;
4145 							}
4146 							else if( nCoreStart <=
4147 									 GetPortionData().GetLastValidCorePosition() )
4148 							{
4149 								DBG_ASSERT(
4150 									GetPortionData().IsValidCorePosition(
4151 																	  nCoreStart ),
4152 									 "problem determining valid core position" );
4153 
4154 								nLocalStart =
4155 									GetPortionData().GetAccessiblePosition(
4156 																	  nCoreStart );
4157 							}
4158 						}
4159 
4160 						// end position
4161 						sal_Int32 nLocalEnd = -1;
4162 						if( nHere < nEndIndex )
4163 						{
4164 							// selection ends in following node:
4165 							// then our local selection extends to the end
4166 							nLocalEnd = GetPortionData().GetAccessibleString().
4167 																	   getLength();
4168 						}
4169 						else
4170 						{
4171 							DBG_ASSERT( nHere == nStartIndex,
4172 										"miscalculated index" );
4173 
4174 							// selection ends in this node: then select everything
4175 							// before our part of the node
4176 							sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex();
4177 							if( nCoreEnd >
4178 									GetPortionData().GetLastValidCorePosition() )
4179 							{
4180 								// selection extends beyond out part of this para
4181 								nLocalEnd = GetPortionData().GetAccessibleString().
4182 																	   getLength();
4183 							}
4184 							else if( nCoreEnd >=
4185 									 GetPortionData().GetFirstValidCorePosition() )
4186 							{
4187 								// selection is inside our part of this para
4188 								DBG_ASSERT(
4189 									GetPortionData().IsValidCorePosition(
4190 																	  nCoreEnd ),
4191 									 "problem determining valid core position" );
4192 
4193 								nLocalEnd = GetPortionData().GetAccessiblePosition(
4194 																	   nCoreEnd );
4195 							}
4196 						}
4197 
4198 						if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
4199 						{
4200 							nStart = nLocalStart;
4201 							nEnd = nLocalEnd;
4202 							bRet = sal_True;
4203 						}
4204 					} // if hit the index
4205 					else
4206 					{
4207 						nSelected--;
4208 					}
4209                 }
4210                 // else: this PaM doesn't point to this paragraph
4211             }
4212             // else: this PaM is collapsed and doesn't select anything
4213 
4214             // next PaM in ring
4215             pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
4216         }
4217         while( !bRet && (pCrsr != pRingStart) );
4218     }
4219     // else: nocursor -> no selection
4220 
4221     if( bRet )
4222     {
4223 		sal_Int32 nCaretPos = GetCaretPos();
4224 		if( nStart == nCaretPos )
4225 		{
4226 			sal_Int32 tmp = nStart;
4227 			nStart = nEnd;
4228 			nEnd = tmp;
4229 		}
4230     }
4231     return bRet;
4232 }
4233 
4234 sal_Int16 SAL_CALL SwAccessibleParagraph::getAccessibleRole (void) throw (::com::sun::star::uno::RuntimeException)
4235 {
4236 	//Get the real heading level, Heading1 ~ Heading10
4237 	if (nHeadingLevel > 0)
4238 	{
4239 		return AccessibleRole::HEADING;
4240 	}
4241 	else
4242 	{
4243 		return AccessibleRole::PARAGRAPH;
4244 	}
4245 }
4246 
4247 // End Add
4248 
4249 
4250 /* This funcion is already defined in accpara.cxx(Added by yanjun)
4251 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
4252 		throw (::com::sun::star::uno::RuntimeException)
4253 {
4254 // Test Code
4255 //     Sequence<OUString> seNames(1);
4256 //     OUString* pStrings = seNames.getArray();
4257 // 	pStrings[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("ParaBackColor"));
4258 //
4259 //     Sequence<Any> aAnys(1);
4260 // 	Reference<XMultiPropertySet> xPortion = CreateUnoPortion( 0, 0 );
4261 //     aAnys = xPortion->getPropertyValues( seNames );
4262 // 	const Any* pAnys = aAnys.getConstArray();
4263 //
4264 // 	sal_uInt32 crColorT=0;
4265 // 	pAnys[0] >>= crColorT;
4266 // End Test Code
4267 
4268 	const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground();
4269 	sal_uInt32 crBack = rBack.GetColor().GetColor();
4270 
4271 	if (COL_AUTO == crBack)
4272 	{
4273 		Reference<XAccessible> xAccDoc = getAccessibleParent();
4274 		if (xAccDoc.is())
4275 		{
4276 			Reference<XAccessibleComponent> xCompoentDoc(xAccDoc,UNO_QUERY);
4277 			if (xCompoentDoc.is())
4278 			{
4279 				crBack = (sal_uInt32)xCompoentDoc->getBackground();
4280 			}
4281 		}
4282 	}
4283 	return crBack;
4284 }
4285 */
4286 
4287 //Get the real heading level, Heading1 ~ Heading10
4288 sal_Int32 SwAccessibleParagraph::GetRealHeadingLevel()
4289 {
4290     uno::Reference< ::com::sun::star::beans::XPropertySet > xPortion = CreateUnoPortion( 0, 0 );
4291     ::rtl::OUString pString = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaStyleName"));
4292     uno::Any styleAny = xPortion->getPropertyValue( pString );
4293     ::rtl::OUString sValue;
4294 	if (styleAny >>= sValue)
4295 	{
4296 		//Modified by yanjun for acc migration
4297 		sal_Int32 length = sValue.getLength/*GetCharCount*/();
4298 		if (length == 9 || length == 10)
4299 		{
4300             ::rtl::OUString headStr = sValue.copy(0, 7);
4301             if (headStr.equals(::rtl::OUString::createFromAscii("Heading")))
4302 			{
4303                 ::rtl::OUString intStr = sValue.copy(8);
4304 				sal_Int32 headingLevel = intStr.toInt32(10);
4305 				return headingLevel;
4306 			}
4307 		}
4308 	}
4309 	return -1;
4310 }
4311 
4312 uno::Any SAL_CALL SwAccessibleParagraph::getExtendedAttributes()
4313 		throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
4314 {
4315     uno::Any Ret;
4316     ::rtl::OUString strHeading(::rtl::OUString::createFromAscii("heading-level:"));
4317 	if( nHeadingLevel >= 0 )
4318 		strHeading += OUString::valueOf(nHeadingLevel, 10);
4319 	strHeading += OUString::createFromAscii(";");
4320 
4321 	Ret <<= strHeading;
4322 
4323 	return Ret;
4324 }
4325 
4326 //Tab will be return when call WORDTYPE
4327 sal_Bool SwAccessibleParagraph::tabCharInWord( sal_Int32 nIndex, i18n::Boundary& aBound)
4328 {
4329 	sal_Bool bFind =  sal_False;
4330 	if( aBound.startPos != nIndex)
4331 	{
4332 		OUString tabStr;
4333 		if(aBound.startPos>nIndex)
4334 			tabStr = GetString().copy(nIndex,(aBound.startPos - nIndex) );
4335 
4336 		sal_Unicode tabChar('\t');
4337 		sal_Int32 tabIndex = tabStr.indexOf(tabChar);
4338 		if( tabIndex > -1 )
4339 		{
4340 			aBound.startPos = nIndex + tabIndex ;
4341 			aBound.endPos = aBound.startPos + 1;
4342 			bFind = sal_True;
4343 		}
4344 	}
4345 	return bFind;
4346 }
4347