xref: /AOO41X/main/sw/source/core/access/accpara.cxx (revision 24c56ab9f1bd1305754aa2f564704f38ff57627e)
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 ) )
1820         throw lang::IndexOutOfBoundsException();
1821 
1822     bool bSupplementalMode = false;
1823     uno::Sequence< ::rtl::OUString > aNames = aRequestedAttributes;
1824     if (aNames.getLength() == 0)
1825     {
1826         bSupplementalMode = true;
1827         aNames = getAttributeNames();
1828     }
1829     // retrieve default character attributes
1830     tAccParaPropValMap aDefAttrSeq;
1831     _getDefaultAttributesImpl( aNames, aDefAttrSeq, true );
1832 
1833     // retrieved run character attributes
1834     tAccParaPropValMap aRunAttrSeq;
1835     _getRunAttributesImpl( nIndex, aNames, aRunAttrSeq );
1836 
1837     // merge default and run attributes
1838     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1839     PropertyValue* pValues = aValues.getArray();
1840     sal_Int32 i = 0;
1841     for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin();
1842           aDefIter != aDefAttrSeq.end();
1843           ++aDefIter )
1844     {
1845         tAccParaPropValMap::const_iterator aRunIter =
1846                                         aRunAttrSeq.find( aDefIter->first );
1847         if ( aRunIter != aRunAttrSeq.end() )
1848         {
1849             pValues[i] = aRunIter->second;
1850         }
1851         else
1852         {
1853             pValues[i] = aDefIter->second;
1854         }
1855         ++i;
1856     }
1857     if( bSupplementalMode )
1858     {
1859         uno::Sequence< ::rtl::OUString > aSupplementalNames = aRequestedAttributes;
1860         if (aSupplementalNames.getLength() == 0)
1861             aSupplementalNames = getSupplementalAttributeNames();
1862 
1863         tAccParaPropValMap aSupplementalAttrSeq;
1864         _getSupplementalAttributesImpl( nIndex, aSupplementalNames, aSupplementalAttrSeq );
1865 
1866         aValues.realloc( aValues.getLength() + aSupplementalAttrSeq.size() );
1867         pValues = aValues.getArray();
1868 
1869         for ( tAccParaPropValMap::const_iterator aSupplementalIter = aSupplementalAttrSeq.begin();
1870             aSupplementalIter != aSupplementalAttrSeq.end();
1871             ++aSupplementalIter )
1872         {
1873             pValues[i] = aSupplementalIter->second;
1874             ++i;
1875         }
1876 
1877         _correctValues( nIndex, aValues );
1878 
1879         aValues.realloc( aValues.getLength() + 1 );
1880 
1881         pValues = aValues.getArray();
1882 
1883         const SwTxtNode* pTxtNode( GetTxtNode() );
1884         PropertyValue& rValue = pValues[aValues.getLength() - 1 ];
1885         rValue.Name = OUString::createFromAscii("NumberingPrefix");
1886         OUString sNumBullet = pTxtNode->GetNumString();
1887         rValue.Value <<= sNumBullet;
1888         rValue.Handle = -1;
1889         rValue.State = PropertyState_DIRECT_VALUE;
1890 
1891         String strTypeName = GetFieldTypeNameAtIndex(nIndex);
1892         if (strTypeName.Len() > 0)
1893         {
1894             aValues.realloc( aValues.getLength() + 1 );
1895             pValues = aValues.getArray();
1896             rValue = pValues[aValues.getLength() - 1];
1897             rValue.Name = OUString::createFromAscii("FieldType");
1898             rValue.Value <<= rtl::OUString(strTypeName.ToLowerAscii());
1899             rValue.Handle = -1;
1900             rValue.State = PropertyState_DIRECT_VALUE;
1901         }
1902 
1903         //sort property values
1904         // build sorted index array
1905         sal_Int32 nLength = aValues.getLength();
1906         const PropertyValue* pPairs = aValues.getConstArray();
1907         sal_Int32* pIndices = new sal_Int32[nLength];
1908         for( i = 0; i < nLength; i++ )
1909             pIndices[i] = i;
1910         sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
1911         // create sorted sequences accoring to index array
1912         uno::Sequence<PropertyValue> aNewValues( nLength );
1913         PropertyValue* pNewValues = aNewValues.getArray();
1914         for( i = 0; i < nLength; i++ )
1915         {
1916             pNewValues[i] = pPairs[pIndices[i]];
1917         }
1918         delete[] pIndices;
1919         return aNewValues;
1920     }
1921 
1922 //    // create a (dummy) text portion for the sole purpose of calling
1923 //    // getPropertyValues on it
1924 //    Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 );
1925 
1926 //    // get values
1927 //    Sequence<OUString> aNames = getAttributeNames();
1928 //    sal_Int32 nLength = aNames.getLength();
1929 //    Sequence<Any> aAnys( nLength );
1930 //    aAnys = xPortion->getPropertyValues( aNames );
1931 
1932 //    // copy names + anys into return sequence
1933 //    Sequence<PropertyValue> aValues( aNames.getLength() );
1934 //    const OUString* pNames = aNames.getConstArray();
1935 //    const Any* pAnys = aAnys.getConstArray();
1936 //    PropertyValue* pValues = aValues.getArray();
1937 //    for( sal_Int32 i = 0; i < nLength; i++ )
1938 //    {
1939 //        PropertyValue& rValue = pValues[i];
1940 //        rValue.Name = pNames[i];
1941 //        rValue.Value = pAnys[i];
1942 //        rValue.Handle = -1;                         // handle not supported
1943 //        rValue.State = PropertyState_DIRECT_VALUE;  // states not supported
1944 //    }
1945 
1946 //    // adjust background color if we're in a gray portion
1947 //    DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name.
1948 //                equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")),
1949 //                "Please adjust CHAR_BACK_COLOR_POS constant." );
1950 //    if( GetPortionData().IsInGrayPortion( nIndex ) )
1951 //        pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
1952 
1953     return aValues;
1954 }
1955 
1956 // --> OD 2006-07-11 #i63870#
1957 void SwAccessibleParagraph::_getDefaultAttributesImpl(
1958         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1959         tAccParaPropValMap& rDefAttrSeq,
1960         const bool bOnlyCharAttrs )
1961 {
1962     // retrieve default attributes
1963     const SwTxtNode* pTxtNode( GetTxtNode() );
1964     ::boost::scoped_ptr<SfxItemSet> pSet;
1965     if ( !bOnlyCharAttrs )
1966     {
1967         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1968                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1969                                RES_PARATR_BEGIN, RES_PARATR_END - 1,
1970                                RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1971                                0 ) );
1972     }
1973     else
1974     {
1975         pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1976                                RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1977                                0 ) );
1978     }
1979     // --> OD 2007-11-12 #i82637#
1980     // From the perspective of the a11y API the default character attributes
1981     // are the character attributes, which are set at the paragraph style
1982     // of the paragraph. The character attributes set at the automatic paragraph
1983     // style of the paragraph are treated as run attributes.
1984 //    pTxtNode->SwCntntNode::GetAttr( *pSet );
1985     // get default paragraph attributes, if needed, and merge these into <pSet>
1986     if ( !bOnlyCharAttrs )
1987     {
1988         SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1989                              RES_PARATR_BEGIN, RES_PARATR_END - 1,
1990                              RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1991                              0 );
1992         pTxtNode->SwCntntNode::GetAttr( aParaSet );
1993         pSet->Put( aParaSet );
1994     }
1995     // get default character attributes and merge these into <pSet>
1996     ASSERT( pTxtNode->GetTxtColl(),
1997             "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" );
1998     if ( pTxtNode->GetTxtColl() )
1999     {
2000         SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
2001                              RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
2002                              0 );
2003         aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() );
2004         pSet->Put( aCharSet );
2005     }
2006     // <--
2007 
2008     // build-up sequence containing the run attributes <rDefAttrSeq>
2009     tAccParaPropValMap aDefAttrSeq;
2010     {
2011         const SfxItemPropertyMap* pPropMap =
2012                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
2013         PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
2014         PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
2015         while ( aPropIt != aPropertyEntries.end() )
2016         {
2017             const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID );
2018             if ( pItem )
2019             {
2020                 uno::Any aVal;
2021                 pItem->QueryValue( aVal, aPropIt->nMemberId );
2022 
2023                 PropertyValue rPropVal;
2024                 rPropVal.Name = aPropIt->sName;
2025                 rPropVal.Value = aVal;
2026                 rPropVal.Handle = -1;
2027                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2028 
2029                 aDefAttrSeq[rPropVal.Name] = rPropVal;
2030             }
2031             ++aPropIt;
2032         }
2033 
2034         // --> OD 2007-01-15 #i72800#
2035         // add property value entry for the paragraph style
2036         if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() )
2037         {
2038             const ::rtl::OUString sParaStyleName =
2039                     ::rtl::OUString::createFromAscii(
2040                             GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName );
2041             if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() )
2042             {
2043                 PropertyValue rPropVal;
2044                 rPropVal.Name = sParaStyleName;
2045                 uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) );
2046                 rPropVal.Value = aVal;
2047                 rPropVal.Handle = -1;
2048                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2049 
2050                 aDefAttrSeq[rPropVal.Name] = rPropVal;
2051             }
2052         }
2053         // <--
2054 
2055         // --> OD 2007-01-15 #i73371#
2056         // resolve value text::WritingMode2::PAGE of property value entry WritingMode
2057         if ( !bOnlyCharAttrs && GetFrm() )
2058         {
2059             const ::rtl::OUString sWritingMode =
2060                     ::rtl::OUString::createFromAscii(
2061                             GetPropName( UNO_NAME_WRITING_MODE ).pName );
2062             tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode );
2063             if ( aIter != aDefAttrSeq.end() )
2064             {
2065                 PropertyValue rPropVal( aIter->second );
2066                 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
2067                 if ( nVal == text::WritingMode2::PAGE )
2068                 {
2069                     const SwFrm* pUpperFrm( GetFrm()->GetUpper() );
2070                     while ( pUpperFrm )
2071                     {
2072                         if ( pUpperFrm->GetType() &
2073                                ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) )
2074                         {
2075                             if ( pUpperFrm->IsVertical() )
2076                             {
2077                                 nVal = text::WritingMode2::TB_RL;
2078                             }
2079                             else if ( pUpperFrm->IsRightToLeft() )
2080                             {
2081                                 nVal = text::WritingMode2::RL_TB;
2082                             }
2083                             else
2084                             {
2085                                 nVal = text::WritingMode2::LR_TB;
2086                             }
2087                             rPropVal.Value <<= nVal;
2088                             aDefAttrSeq[rPropVal.Name] = rPropVal;
2089                             break;
2090                         }
2091 
2092                         if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) )
2093                         {
2094                             pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm();
2095                         }
2096                         else
2097                         {
2098                             pUpperFrm = pUpperFrm->GetUpper();
2099                         }
2100                     }
2101                 }
2102             }
2103         }
2104         // <--
2105     }
2106 
2107     if ( aRequestedAttributes.getLength() == 0 )
2108     {
2109         rDefAttrSeq = aDefAttrSeq;
2110     }
2111     else
2112     {
2113         const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
2114         const sal_Int32 nLength = aRequestedAttributes.getLength();
2115         for( sal_Int32 i = 0; i < nLength; ++i )
2116         {
2117             tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] );
2118             if ( aIter != aDefAttrSeq.end() )
2119             {
2120                 rDefAttrSeq[ aIter->first ] = aIter->second;
2121             }
2122         }
2123     }
2124 }
2125 
2126 uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
2127         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
2128         throw ( uno::RuntimeException )
2129 {
2130     vos::OGuard aGuard(Application::GetSolarMutex());
2131     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2132 
2133     tAccParaPropValMap aDefAttrSeq;
2134     _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
2135 
2136     // --> OD 2010-03-08 #i92233#
2137     static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "MMToPixelRatio" ) );
2138     bool bProvideMMToPixelRatio( false );
2139     {
2140         if ( aRequestedAttributes.getLength() == 0 )
2141         {
2142             bProvideMMToPixelRatio = true;
2143         }
2144         else
2145         {
2146             const rtl::OUString* aRequestedAttrIter =
2147                   ::std::find( ::comphelper::stl_begin( aRequestedAttributes ),
2148                                ::comphelper::stl_end( aRequestedAttributes ),
2149                                sMMToPixelRatio );
2150             if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) )
2151             {
2152                 bProvideMMToPixelRatio = true;
2153             }
2154         }
2155     }
2156     // <--
2157 
2158     uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() +
2159                                             ( bProvideMMToPixelRatio ? 1 : 0 ) );
2160     PropertyValue* pValues = aValues.getArray();
2161     sal_Int32 i = 0;
2162     for ( tAccParaPropValMap::const_iterator aIter  = aDefAttrSeq.begin();
2163           aIter != aDefAttrSeq.end();
2164           ++aIter )
2165     {
2166         pValues[i] = aIter->second;
2167         ++i;
2168     }
2169 
2170     // --> OD 2010-03-08 #i92233#
2171     if ( bProvideMMToPixelRatio )
2172     {
2173         PropertyValue rPropVal;
2174         rPropVal.Name = sMMToPixelRatio;
2175         const Size a100thMMSize( 1000, 1000 );
2176         const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize );
2177         const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width();
2178         rPropVal.Value = uno::makeAny( fRatio );
2179         rPropVal.Handle = -1;
2180         rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2181         pValues[ aValues.getLength() - 1 ] = rPropVal;
2182     }
2183     // <--
2184 
2185     return aValues;
2186 }
2187 
2188 void SwAccessibleParagraph::_getRunAttributesImpl(
2189         const sal_Int32 nIndex,
2190         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
2191         tAccParaPropValMap& rRunAttrSeq )
2192 {
2193     // create PaM for character at position <nIndex>
2194     SwPaM* pPaM( 0 );
2195     {
2196         const SwTxtNode* pTxtNode( GetTxtNode() );
2197         SwPosition* pStartPos = new SwPosition( *pTxtNode );
2198         pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) );
2199         SwPosition* pEndPos = new SwPosition( *pTxtNode );
2200         pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) );
2201 
2202         pPaM = new SwPaM( *pStartPos, *pEndPos );
2203 
2204         delete pStartPos;
2205         delete pEndPos;
2206     }
2207 
2208     // retrieve character attributes for the created PaM <pPaM>
2209     SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(),
2210                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
2211                      0 );
2212     // --> OD 2007-11-12 #i82637#
2213     // From the perspective of the a11y API the character attributes, which
2214     // are set at the automatic paragraph style of the paragraph are treated
2215     // as run attributes.
2216 //    SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True );
2217     // get character attributes from automatic paragraph style and merge these into <aSet>
2218     {
2219         const SwTxtNode* pTxtNode( GetTxtNode() );
2220         if ( pTxtNode->HasSwAttrSet() )
2221         {
2222             SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(),
2223                                                      RES_CHRATR_BEGIN, RES_CHRATR_END -1,
2224                                                      0 );
2225             aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False );
2226             aSet.Put( aAutomaticParaStyleCharAttrs );
2227         }
2228     }
2229     // get character attributes at <pPaM> and merge these into <aSet>
2230     {
2231         SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(),
2232                                     RES_CHRATR_BEGIN, RES_CHRATR_END -1,
2233                                     0 );
2234         SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True);
2235         aSet.Put( aCharAttrsAtPaM );
2236     }
2237     // <--
2238 
2239     // build-up sequence containing the run attributes <rRunAttrSeq>
2240     {
2241         tAccParaPropValMap aRunAttrSeq;
2242         {
2243             // --> OD 2007-11-12 #i82637#
2244             tAccParaPropValMap aDefAttrSeq;
2245             uno::Sequence< ::rtl::OUString > aDummy;
2246             _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true );
2247             // <--
2248 
2249             const SfxItemPropertyMap* pPropMap =
2250                     aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
2251             PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
2252             PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
2253             while ( aPropIt != aPropertyEntries.end() )
2254             {
2255                 const SfxPoolItem* pItem( 0 );
2256                 // --> OD 2007-11-12 #i82637#
2257                 // Found character attributes, whose value equals the value of
2258                 // the corresponding default character attributes, are excluded.
2259                 if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET )
2260                 {
2261                     uno::Any aVal;
2262                     pItem->QueryValue( aVal, aPropIt->nMemberId );
2263 
2264                     PropertyValue rPropVal;
2265                     rPropVal.Name = aPropIt->sName;
2266                     rPropVal.Value = aVal;
2267                     rPropVal.Handle = -1;
2268                     rPropVal.State = PropertyState_DIRECT_VALUE;
2269 
2270                     tAccParaPropValMap::const_iterator aDefIter =
2271                                             aDefAttrSeq.find( rPropVal.Name );
2272                     if ( aDefIter == aDefAttrSeq.end() ||
2273                          rPropVal.Value != aDefIter->second.Value )
2274                     {
2275                         aRunAttrSeq[rPropVal.Name] = rPropVal;
2276                     }
2277                 }
2278 
2279                 ++aPropIt;
2280             }
2281         }
2282 
2283         if ( aRequestedAttributes.getLength() == 0 )
2284         {
2285             rRunAttrSeq = aRunAttrSeq;
2286         }
2287         else
2288         {
2289             const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray();
2290             const sal_Int32 nLength = aRequestedAttributes.getLength();
2291             for( sal_Int32 i = 0; i < nLength; ++i )
2292             {
2293                 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
2294                 if ( aIter != aRunAttrSeq.end() )
2295                 {
2296                     rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
2297                 }
2298             }
2299         }
2300     }
2301 
2302     delete pPaM;
2303 }
2304 
2305 uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
2306         sal_Int32 nIndex,
2307         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
2308         throw ( lang::IndexOutOfBoundsException,
2309                 uno::RuntimeException )
2310 {
2311     vos::OGuard aGuard(Application::GetSolarMutex());
2312     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2313 
2314     {
2315         const ::rtl::OUString& rText = GetString();
2316         if ( !IsValidChar( nIndex, rText.getLength() ) )
2317         {
2318             throw lang::IndexOutOfBoundsException();
2319         }
2320     }
2321 
2322     tAccParaPropValMap aRunAttrSeq;
2323     _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
2324 
2325     uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() );
2326     PropertyValue* pValues = aValues.getArray();
2327     sal_Int32 i = 0;
2328     for ( tAccParaPropValMap::const_iterator aIter  = aRunAttrSeq.begin();
2329           aIter != aRunAttrSeq.end();
2330           ++aIter )
2331     {
2332         pValues[i] = aIter->second;
2333         ++i;
2334     }
2335 
2336     return aValues;
2337 }
2338 // <--
2339 void SwAccessibleParagraph::_getSupplementalAttributesImpl(
2340         const sal_Int32,
2341         const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
2342         tAccParaPropValMap& rSupplementalAttrSeq )
2343 {
2344     const SwTxtNode* pTxtNode( GetTxtNode() );
2345     ::boost::scoped_ptr<SfxItemSet> pSet;
2346     pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
2347         RES_PARATR_ADJUST, RES_PARATR_ADJUST,
2348         RES_PARATR_TABSTOP, RES_PARATR_TABSTOP,
2349         RES_PARATR_LINESPACING, RES_PARATR_LINESPACING,
2350         RES_UL_SPACE, RES_UL_SPACE,
2351         RES_LR_SPACE, RES_LR_SPACE,
2352         RES_PARATR_NUMRULE, RES_PARATR_NUMRULE,
2353         RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
2354         0 ) );
2355 
2356     if ( pTxtNode->HasBullet() || pTxtNode->HasNumber() )
2357     {
2358         pSet->Put( pTxtNode->GetAttr(RES_PARATR_LIST_LEVEL, RES_PARATR_LIST_LEVEL) );
2359     }
2360     pSet->Put( pTxtNode->SwCntntNode::GetAttr(RES_UL_SPACE) );
2361     pSet->Put( pTxtNode->SwCntntNode::GetAttr(RES_LR_SPACE) );
2362     pSet->Put( pTxtNode->SwCntntNode::GetAttr(RES_PARATR_ADJUST) );
2363 
2364     tAccParaPropValMap aSupplementalAttrSeq;
2365     {
2366 //        const SfxItemPropertySet& rPropSet =
2367 //                    aSwMapProvider.GetPropertyMap( PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE );
2368 //        const SfxItemPropertyMap* pPropMap( rPropSet.getPropertyMap() );
2369         const SfxItemPropertyMapEntry* pPropMap(
2370                 aSwMapProvider.GetPropertyMapEntries( PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE ) );
2371         while ( pPropMap->pName )
2372         {
2373             const SfxPoolItem* pItem = pSet->GetItem( pPropMap->nWID );
2374             if ( pItem )
2375             {
2376                 uno::Any aVal;
2377                 pItem->QueryValue( aVal, pPropMap->nMemberId );
2378 
2379                 PropertyValue rPropVal;
2380                 rPropVal.Name = OUString::createFromAscii( pPropMap->pName );
2381                 rPropVal.Value = aVal;
2382                 rPropVal.Handle = -1;
2383                 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
2384 
2385                 aSupplementalAttrSeq[rPropVal.Name] = rPropVal;
2386             }
2387 
2388             ++pPropMap;
2389         }
2390     }
2391 
2392     const OUString* pSupplementalAttrs = aRequestedAttributes.getConstArray();
2393     const sal_Int32 nSupplementalLength = aRequestedAttributes.getLength();
2394 
2395     for( sal_Int32 index = 0; index < nSupplementalLength; ++index )
2396     {
2397         tAccParaPropValMap::const_iterator const aIter = aSupplementalAttrSeq.find( pSupplementalAttrs[index] );
2398         if ( aIter != aSupplementalAttrSeq.end() )
2399         {
2400             rSupplementalAttrSeq[ aIter->first ] = aIter->second;
2401         }
2402     }
2403 }
2404 
2405 void SwAccessibleParagraph::_correctValues( const sal_Int32 nIndex,
2406                                            uno::Sequence< PropertyValue >& rValues)
2407 {
2408     PropertyValue ChangeAttr, ChangeAttrColor;
2409 
2410     const SwRedline* pRedline = GetRedlineAtIndex( nIndex );
2411     if ( pRedline )
2412     {
2413 
2414         const SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig();
2415         AuthorCharAttr aChangeAttr;
2416         if ( pOpt )
2417         {
2418             switch( pRedline->GetType())
2419             {
2420             case nsRedlineType_t::REDLINE_INSERT:
2421                 aChangeAttr = pOpt->GetInsertAuthorAttr();
2422                 break;
2423             case nsRedlineType_t::REDLINE_DELETE:
2424                 aChangeAttr = pOpt->GetDeletedAuthorAttr();
2425                 break;
2426             case nsRedlineType_t::REDLINE_FORMAT:
2427                 aChangeAttr = pOpt->GetFormatAuthorAttr();
2428                 break;
2429             }
2430         }
2431         switch( aChangeAttr.nItemId )
2432         {
2433         case SID_ATTR_CHAR_WEIGHT:
2434             ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_WEIGHT).pName );
2435             ChangeAttr.Value <<= awt::FontWeight::BOLD;
2436             break;
2437         case SID_ATTR_CHAR_POSTURE:
2438             ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_POSTURE).pName );
2439             ChangeAttr.Value <<= awt::FontSlant_ITALIC; //char posture
2440             break;
2441         case SID_ATTR_CHAR_STRIKEOUT:
2442             ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_STRIKEOUT).pName );
2443             ChangeAttr.Value <<= awt::FontStrikeout::SINGLE; //char strikeout
2444             break;
2445         case SID_ATTR_CHAR_UNDERLINE:
2446             ChangeAttr.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_UNDERLINE).pName );
2447             ChangeAttr.Value <<= aChangeAttr.nAttr; //underline line
2448             break;
2449         }
2450         if( aChangeAttr.nColor != COL_NONE )
2451         {
2452             if( aChangeAttr.nItemId == SID_ATTR_BRUSH )
2453             {
2454                 ChangeAttrColor.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_BACK_COLOR).pName );
2455                 if( aChangeAttr.nColor == COL_TRANSPARENT )//char backcolor
2456                     ChangeAttrColor.Value <<= COL_BLUE;
2457                 else
2458                     ChangeAttrColor.Value <<= aChangeAttr.nColor;
2459             }
2460             else
2461             {
2462                 ChangeAttrColor.Name = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_COLOR ).pName );
2463                 if( aChangeAttr.nColor == COL_TRANSPARENT )//char color
2464                     ChangeAttrColor.Value <<= COL_BLUE;
2465                 else
2466                     ChangeAttrColor.Value <<= aChangeAttr.nColor;
2467             }
2468         }
2469     }
2470 
2471     PropertyValue* pValues = rValues.getArray();
2472 
2473     const SwTxtNode* pTxtNode( GetTxtNode() );
2474 
2475     sal_Int32 nValues = rValues.getLength();
2476     for (sal_Int32 i = 0;  i < nValues;  ++i)
2477     {
2478         PropertyValue& rValue = pValues[i];
2479 
2480         if (rValue.Name.compareTo( ChangeAttr.Name )==0)
2481         {
2482             rValue.Value = ChangeAttr.Value;
2483             continue;
2484         }
2485 
2486         if (rValue.Name.compareTo( ChangeAttrColor.Name )==0)
2487         {
2488             rValue.Value = ChangeAttr.Value;
2489             continue;
2490         }
2491 
2492         //back color
2493         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_BACK_COLOR ).pName ) )==0)
2494         {
2495             uno::Any &anyChar = rValue.Value;
2496             sal_uInt32 crBack = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
2497             if (COL_AUTO == crBack)
2498             {
2499                 uno::Reference<XAccessibleComponent> xComponent(this);
2500                 if (xComponent.is())
2501                 {
2502                     crBack = (sal_uInt32)xComponent->getBackground();
2503                 }
2504                 rValue.Value <<= crBack;
2505             }
2506             continue;
2507         }
2508 
2509         //char color
2510         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_COLOR ).pName ) )==0)
2511         {
2512             if( GetPortionData().IsInGrayPortion( nIndex ) )
2513                  rValue.Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
2514             uno::Any &anyChar = rValue.Value;
2515             sal_uInt32 crChar = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
2516 
2517             if( COL_AUTO == crChar )
2518             {
2519                 uno::Reference<XAccessibleComponent> xComponent(this);
2520                 if (xComponent.is())
2521                 {
2522                     Color cr(xComponent->getBackground());
2523                     crChar = cr.IsDark() ? COL_WHITE : COL_BLACK;
2524                     rValue.Value <<= crChar;
2525                 }
2526             }
2527             continue;
2528         }
2529 
2530         // UnderLine
2531         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_UNDERLINE ).pName ) )==0)
2532         {
2533             //misspelled word
2534             SwCrsrShell* pCrsrShell = GetCrsrShell();
2535             if( pCrsrShell != NULL && pCrsrShell->GetViewOptions() && pCrsrShell->GetViewOptions()->IsOnlineSpell())
2536             {
2537                 const SwWrongList* pWrongList = pTxtNode->GetWrong();
2538                 if( NULL != pWrongList )
2539                 {
2540                     xub_StrLen nBegin = nIndex;
2541                     xub_StrLen nLen = 1;
2542                     if( pWrongList->InWrongWord(nBegin,nLen) && !pTxtNode->IsSymbol(nBegin) )
2543                     {
2544                         rValue.Value <<= (sal_uInt16)UNDERLINE_WAVE;
2545                     }
2546                 }
2547             }
2548             continue;
2549         }
2550 
2551         // UnderLineColor
2552         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_UNDERLINE_COLOR ).pName ) )==0)
2553         {
2554             //misspelled word
2555             SwCrsrShell* pCrsrShell = GetCrsrShell();
2556             if( pCrsrShell != NULL && pCrsrShell->GetViewOptions() && pCrsrShell->GetViewOptions()->IsOnlineSpell())
2557             {
2558                 const SwWrongList* pWrongList = pTxtNode->GetWrong();
2559                 if( NULL != pWrongList )
2560                 {
2561                     xub_StrLen nBegin = nIndex;
2562                     xub_StrLen nLen = 1;
2563                     if( pWrongList->InWrongWord(nBegin,nLen) && !pTxtNode->IsSymbol(nBegin) )
2564                     {
2565                         rValue.Value <<= (sal_Int32)0x00ff0000;
2566                         continue;
2567                     }
2568                 }
2569             }
2570 
2571             uno::Any &anyChar = rValue.Value;
2572             sal_uInt32 crUnderline = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
2573             if ( COL_AUTO == crUnderline )
2574             {
2575                 uno::Reference<XAccessibleComponent> xComponent(this);
2576                 if (xComponent.is())
2577                 {
2578                     Color cr(xComponent->getBackground());
2579                     crUnderline = cr.IsDark() ? COL_WHITE : COL_BLACK;
2580                     rValue.Value <<= crUnderline;
2581                 }
2582             }
2583 
2584             continue;
2585         }
2586 
2587         //tab stop
2588         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_TABSTOPS ).pName ) )==0)
2589         {
2590             com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > tabs = GetCurrentTabStop( nIndex );
2591             if( !tabs.hasElements() )
2592             {
2593                 tabs.realloc(1);
2594                 ::com::sun::star::style::TabStop ts;
2595                 com::sun::star::awt::Rectangle rc0 = getCharacterBounds(0);
2596                 com::sun::star::awt::Rectangle rc1 = getCharacterBounds(nIndex);
2597                 if( rc1.X - rc0.X >= 48 )
2598                     ts.Position = (rc1.X - rc0.X) - (rc1.X - rc0.X - 48)% 47 + 47;
2599                 else
2600                     ts.Position = 48;
2601                 ts.DecimalChar = ' ';
2602                 ts.FillChar = ' ';
2603                 ts.Alignment = ::com::sun::star::style::TabAlign_LEFT;
2604                 tabs[0] = ts;
2605             }
2606             rValue.Value <<= tabs;
2607             continue;
2608         }
2609 
2610         //number bullet
2611         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_NUMBERING_RULES ).pName ) )==0)
2612         {
2613             if ( pTxtNode->HasBullet() || pTxtNode->HasNumber() )
2614             {
2615                 uno::Any aVal;
2616                 SwNumRule* pNumRule = pTxtNode->GetNumRule();
2617                 if (pNumRule)
2618                 {
2619                     uno::Reference< container::XIndexReplace >  xNum = new SwXNumberingRules(*pNumRule);
2620                     aVal.setValue(&xNum, ::getCppuType((const uno::Reference< container::XIndexReplace >*)0));
2621                 }
2622                 rValue.Value <<= aVal;
2623             }
2624             continue;
2625         }
2626 
2627         //footnote & endnote
2628         if (rValue.Name.compareTo(::rtl::OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_ESCAPEMENT ).pName ) )==0)
2629         {
2630             if ( GetPortionData().IsIndexInFootnode(nIndex) )
2631             {
2632                 const OUString sEscapmentName = OUString::createFromAscii( GetPropName( UNO_NAME_CHAR_ESCAPEMENT ).pName );
2633                 rValue.Value <<= (sal_Int32)101;
2634             }
2635             continue;
2636         }
2637     }
2638 }
2639 
2640 awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
2641     sal_Int32 nIndex )
2642     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2643 {
2644     vos::OGuard aGuard(Application::GetSolarMutex());
2645 
2646     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2647 
2648 
2649     /*  #i12332# The position after the string needs special treatment.
2650         IsValidChar -> IsValidPosition
2651     */
2652     if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
2653         throw lang::IndexOutOfBoundsException();
2654 
2655     /*  #i12332#  */
2656     sal_Bool bBehindText = sal_False;
2657     if ( nIndex == GetString().getLength() )
2658         bBehindText = sal_True;
2659 
2660     // get model position & prepare GetCharRect() arguments
2661     SwCrsrMoveState aMoveState;
2662     aMoveState.bRealHeight = sal_True;
2663     aMoveState.bRealWidth = sal_True;
2664     SwSpecialPos aSpecialPos;
2665     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2666 
2667     sal_uInt16 nPos = 0;
2668 
2669     /*  #i12332# FillSpecialPos does not accept nIndex ==
2670          GetString().getLength(). In that case nPos is set to the
2671          length of the string in the core. This way GetCharRect
2672          returns the rectangle for a cursor at the end of the
2673          paragraph. */
2674     if (bBehindText)
2675     {
2676         nPos = pNode->GetTxt().Len();
2677     }
2678     else
2679         nPos = GetPortionData().FillSpecialPos
2680             (nIndex, aSpecialPos, aMoveState.pSpecialPos );
2681 
2682     // call GetCharRect
2683     SwRect aCoreRect;
2684     SwIndex aIndex( pNode, nPos );
2685     SwPosition aPosition( *pNode, aIndex );
2686     GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
2687 
2688     // translate core coordinates into accessibility coordinates
2689     Window *pWin = GetWindow();
2690     CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2691 
2692     Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
2693     SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2694 
2695     Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
2696     aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
2697 
2698     // convert into AWT Rectangle
2699     return awt::Rectangle(
2700         aScreenRect.Left(), aScreenRect.Top(),
2701         aScreenRect.GetWidth(), aScreenRect.GetHeight() );
2702 }
2703 
2704 sal_Int32 SwAccessibleParagraph::getCharacterCount()
2705     throw (uno::RuntimeException)
2706 {
2707     vos::OGuard aGuard(Application::GetSolarMutex());
2708 
2709     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2710 
2711     return GetString().getLength();
2712 }
2713 
2714 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
2715     throw (uno::RuntimeException)
2716 {
2717     vos::OGuard aGuard(Application::GetSolarMutex());
2718 
2719 
2720     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2721 
2722     // construct SwPosition (where GetCrsrOfst() will put the result into)
2723     SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2724     SwIndex aIndex( pNode, 0);
2725     SwPosition aPos( *pNode, aIndex );
2726 
2727     // construct Point (translate into layout coordinates)
2728     Window *pWin = GetWindow();
2729     CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2730     Point aPoint( rPoint.X, rPoint.Y );
2731     SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root
2732     Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
2733     aPoint.X() += aPixPos.X();
2734     aPoint.Y() += aPixPos.Y();
2735     MapMode aMapMode = pWin->GetMapMode();
2736     Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
2737     if( !aLogBounds.IsInside( aCorePoint ) )
2738     {
2739         /* #i12332# rPoint is may also be in rectangle returned by
2740             getCharacterBounds(getCharacterCount() */
2741 
2742         awt::Rectangle aRectEndPos =
2743             getCharacterBounds(getCharacterCount());
2744 
2745         if (rPoint.X - aRectEndPos.X >= 0 &&
2746             rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
2747             rPoint.Y - aRectEndPos.Y >= 0 &&
2748             rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
2749             return getCharacterCount();
2750 
2751         return -1;
2752     }
2753 
2754     // ask core for position
2755     DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
2756     DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
2757     const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2758     SwCrsrMoveState aMoveState;
2759     aMoveState.bPosMatchesBounds = sal_True;
2760     sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState );
2761 
2762     SwIndex aCntntIdx = aPos.nContent;
2763     const xub_StrLen nIndex = aCntntIdx.GetIndex();
2764     if ( nIndex > 0 )
2765     {
2766         SwRect aResultRect;
2767         pFrm->GetCharRect( aResultRect, aPos );
2768         bool bVert = pFrm->IsVertical();
2769         bool bR2L = pFrm->IsRightToLeft();
2770 
2771         if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) ||
2772              ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) ||
2773              ( bR2L  && aResultRect.Right()   < aCorePoint.X()) )
2774         {
2775             SwIndex aIdxPrev( pNode, nIndex - 1);
2776             SwPosition aPosPrev( *pNode, aIdxPrev );
2777             SwRect aResultRectPrev;
2778             pFrm->GetCharRect( aResultRectPrev, aPosPrev );
2779             if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ||
2780                  ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) ||
2781                  (  bR2L && aResultRectPrev.Right()   > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) )
2782                 aPos = aPosPrev;
2783         }
2784     }
2785 
2786     return bSuccess ?
2787         GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() )
2788         : -1L;
2789 }
2790 
2791 ::rtl::OUString SwAccessibleParagraph::getSelectedText()
2792     throw (uno::RuntimeException)
2793 {
2794     vos::OGuard aGuard(Application::GetSolarMutex());
2795 
2796     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2797 
2798     sal_Int32 nStart, nEnd;
2799     sal_Bool bSelected = GetSelection( nStart, nEnd );
2800     return bSelected
2801            ? GetString().copy( nStart, nEnd - nStart )
2802            : ::rtl::OUString();
2803 }
2804 
2805 sal_Int32 SwAccessibleParagraph::getSelectionStart()
2806     throw (uno::RuntimeException)
2807 {
2808     vos::OGuard aGuard(Application::GetSolarMutex());
2809 
2810     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2811 
2812     sal_Int32 nStart, nEnd;
2813     GetSelection( nStart, nEnd );
2814     return nStart;
2815 }
2816 
2817 sal_Int32 SwAccessibleParagraph::getSelectionEnd()
2818     throw (uno::RuntimeException)
2819 {
2820     vos::OGuard aGuard(Application::GetSolarMutex());
2821 
2822     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2823 
2824     sal_Int32 nStart, nEnd;
2825     GetSelection( nStart, nEnd );
2826     return nEnd;
2827 }
2828 
2829 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2830     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2831 {
2832     vos::OGuard aGuard(Application::GetSolarMutex());
2833 
2834     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2835 
2836     // parameter checking
2837     sal_Int32 nLength = GetString().getLength();
2838     if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
2839     {
2840         throw lang::IndexOutOfBoundsException();
2841     }
2842 
2843     sal_Bool bRet = sal_False;
2844 
2845     // get cursor shell
2846     SwCrsrShell* pCrsrShell = GetCrsrShell();
2847     if( pCrsrShell != NULL )
2848     {
2849         // create pam for selection
2850         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2851         SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex));
2852         SwPosition aStartPos( *pNode, aIndex );
2853         SwPaM aPaM( aStartPos );
2854         aPaM.SetMark();
2855         aPaM.GetPoint()->nContent =
2856             GetPortionData().GetModelPosition(nEndIndex);
2857 
2858         // set PaM at cursor shell
2859         bRet = Select( aPaM );
2860     }
2861 
2862     return bRet;
2863 }
2864 
2865 ::rtl::OUString SwAccessibleParagraph::getText()
2866     throw (uno::RuntimeException)
2867 {
2868     vos::OGuard aGuard(Application::GetSolarMutex());
2869 
2870     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2871 
2872     return GetString();
2873 }
2874 
2875 ::rtl::OUString SwAccessibleParagraph::getTextRange(
2876     sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2877     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2878 {
2879     vos::OGuard aGuard(Application::GetSolarMutex());
2880 
2881     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2882 
2883     ::rtl::OUString sText( GetString() );
2884 
2885     if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
2886     {
2887         OrderRange( nStartIndex, nEndIndex );
2888         return sText.copy(nStartIndex, nEndIndex-nStartIndex );
2889     }
2890     else
2891         throw lang::IndexOutOfBoundsException();
2892 }
2893 
2894 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
2895 {
2896     vos::OGuard aGuard(Application::GetSolarMutex());
2897 
2898     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2899 
2900     /*accessibility::*/TextSegment aResult;
2901     aResult.SegmentStart = -1;
2902     aResult.SegmentEnd = -1;
2903 
2904     const ::rtl::OUString rText = GetString();
2905     // implement the silly specification that first position after
2906     // text must return an empty string, rather than throwing an
2907     // IndexOutOfBoundsException, except for LINE, where the last
2908     // line is returned
2909     if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
2910         return aResult;
2911 
2912     // with error checking
2913     i18n::Boundary aBound;
2914     sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2915 
2916     DBG_ASSERT( aBound.startPos >= 0,               "illegal boundary" );
2917     DBG_ASSERT( aBound.startPos <= aBound.endPos,   "illegal boundary" );
2918 
2919     // return word (if present)
2920     if ( bWord )
2921     {
2922         aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2923         aResult.SegmentStart = aBound.startPos;
2924         aResult.SegmentEnd = aBound.endPos;
2925     }
2926 
2927     return aResult;
2928 }
2929 
2930 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
2931 {
2932     vos::OGuard aGuard(Application::GetSolarMutex());
2933 
2934     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2935 
2936     const ::rtl::OUString rText = GetString();
2937 
2938     /*accessibility::*/TextSegment aResult;
2939     aResult.SegmentStart = -1;
2940     aResult.SegmentEnd = -1;
2941     //If nIndex = 0, then nobefore text so return -1 directly.
2942     if( nIndex == 0 )
2943             return aResult;
2944     //Tab will be return when call WORDTYPE
2945 
2946     // get starting pos
2947     i18n::Boundary aBound;
2948     if (nIndex ==  rText.getLength())
2949         aBound.startPos = aBound.endPos = nIndex;
2950     else
2951     {
2952         sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
2953 
2954         if ( ! bTmp )
2955             aBound.startPos = aBound.endPos = nIndex;
2956     }
2957 
2958     // now skip to previous word
2959     if (nTextType==2 || nTextType == 3)
2960     {
2961         i18n::Boundary preBound = aBound;
2962         while(preBound.startPos==aBound.startPos && nIndex > 0)
2963         {
2964             nIndex = min( nIndex, preBound.startPos ) - 1;
2965             if( nIndex < 0 ) break;
2966             GetTextBoundary( preBound, rText, nIndex, nTextType );
2967         }
2968         //if (nIndex>0)
2969         if (nIndex>=0)
2970         //Tab will be return when call WORDTYPE
2971         {
2972             aResult.SegmentText = rText.copy( preBound.startPos, preBound.endPos - preBound.startPos );
2973             aResult.SegmentStart = preBound.startPos;
2974             aResult.SegmentEnd = preBound.endPos;
2975         }
2976     }
2977     else
2978     {
2979         sal_Bool bWord = sal_False;
2980         while( !bWord )
2981         {
2982             nIndex = min( nIndex, aBound.startPos ) - 1;
2983             if( nIndex >= 0 )
2984             {
2985                 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2986             }
2987             else
2988                 break;  // exit if beginning of string is reached
2989         }
2990 
2991         if (bWord && nIndex<rText.getLength())
2992         {
2993             aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2994             aResult.SegmentStart = aBound.startPos;
2995             aResult.SegmentEnd = aBound.endPos;
2996         }
2997     }
2998     return aResult;
2999 }
3000 
3001 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
3002 {
3003     vos::OGuard aGuard(Application::GetSolarMutex());
3004 
3005     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3006 
3007     /*accessibility::*/TextSegment aResult;
3008     aResult.SegmentStart = -1;
3009     aResult.SegmentEnd = -1;
3010     const ::rtl::OUString rText = GetString();
3011 
3012     // implement the silly specification that first position after
3013     // text must return an empty string, rather than throwing an
3014     // IndexOutOfBoundsException
3015     if( nIndex == rText.getLength() )
3016         return aResult;
3017 
3018 
3019     // get first word, then skip to next word
3020     i18n::Boundary aBound;
3021     GetTextBoundary( aBound, rText, nIndex, nTextType );
3022     sal_Bool bWord = sal_False;
3023     while( !bWord )
3024     {
3025         nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
3026         if( nIndex < rText.getLength() )
3027             bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
3028         else
3029             break;  // exit if end of string is reached
3030     }
3031 
3032     if ( bWord )
3033     {
3034         aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
3035         aResult.SegmentStart = aBound.startPos;
3036         aResult.SegmentEnd = aBound.endPos;
3037     }
3038 
3039 /*
3040         sal_Bool bWord = sal_False;
3041     bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
3042 
3043         if (nTextType==2)
3044         {
3045                 Boundary nexBound=aBound;
3046 
3047         // real current word
3048         if( nIndex <= aBound.endPos && nIndex >= aBound.startPos )
3049         {
3050             while(nexBound.endPos==aBound.endPos&&nIndex<rText.getLength())
3051             {
3052                 // nIndex = max( (sal_Int32)(nIndex), nexBound.endPos) + 1;
3053                 nIndex = max( (sal_Int32)(nIndex), nexBound.endPos) ;
3054                 const sal_Unicode* pStr = rText.getStr();
3055                 if (pStr)
3056                 {
3057                     if( pStr[nIndex] == sal_Unicode(' ') )
3058                         nIndex++;
3059                 }
3060                 if( nIndex < rText.getLength() )
3061                 {
3062                     bWord = GetTextBoundary( nexBound, rText, nIndex, nTextType );
3063                 }
3064             }
3065         }
3066 
3067         if (bWord && nIndex<rText.getLength())
3068         {
3069             aResult.SegmentText = rText.copy( nexBound.startPos, nexBound.endPos - nexBound.startPos );
3070             aResult.SegmentStart = nexBound.startPos;
3071             aResult.SegmentEnd = nexBound.endPos;
3072         }
3073 
3074     }
3075     else
3076     {
3077         bWord = sal_False;
3078         while( !bWord )
3079         {
3080             nIndex = max( (sal_Int32)(nIndex+1), aBound.endPos );
3081             if( nIndex < rText.getLength() )
3082             {
3083                 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
3084             }
3085             else
3086                 break;  // exit if end of string is reached
3087         }
3088         if (bWord && nIndex<rText.getLength())
3089         {
3090             aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
3091             aResult.SegmentStart = aBound.startPos;
3092             aResult.SegmentEnd = aBound.endPos;
3093         }
3094     }
3095 */
3096     return aResult;
3097 }
3098 
3099 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
3100     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3101 {
3102     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3103     vos::OGuard aGuard(Application::GetSolarMutex());
3104 
3105     // select and copy (through dispatch mechanism)
3106     setSelection( nStartIndex, nEndIndex );
3107     ExecuteAtViewShell( SID_COPY );
3108     return sal_True;
3109 }
3110 
3111 
3112 //
3113 //=====  XAccesibleEditableText  ==========================================
3114 //
3115 
3116 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
3117     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3118 {
3119     CHECK_FOR_DEFUNC( XAccessibleEditableText );
3120     vos::OGuard aGuard(Application::GetSolarMutex());
3121 
3122     if( !IsEditableState() )
3123         return sal_False;
3124 
3125     // select and cut (through dispatch mechanism)
3126     setSelection( nStartIndex, nEndIndex );
3127     ExecuteAtViewShell( SID_CUT );
3128     return sal_True;
3129 }
3130 
3131 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
3132     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3133 {
3134     CHECK_FOR_DEFUNC( XAccessibleEditableText );
3135     vos::OGuard aGuard(Application::GetSolarMutex());
3136 
3137     if( !IsEditableState() )
3138         return sal_False;
3139 
3140     // select and paste (through dispatch mechanism)
3141     setSelection( nIndex, nIndex );
3142     ExecuteAtViewShell( SID_PASTE );
3143     return sal_True;
3144 }
3145 
3146 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
3147     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3148 {
3149     return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() );
3150 }
3151 
3152 sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex )
3153     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3154 {
3155     return replaceText( nIndex, nIndex, sText );
3156 }
3157 
3158 sal_Bool SwAccessibleParagraph::replaceText(
3159     sal_Int32 nStartIndex, sal_Int32 nEndIndex,
3160     const ::rtl::OUString& sReplacement )
3161     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3162 {
3163     vos::OGuard aGuard(Application::GetSolarMutex());
3164 
3165     CHECK_FOR_DEFUNC( XAccessibleEditableText );
3166 
3167     const ::rtl::OUString& rText = GetString();
3168 
3169     if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
3170     {
3171         if( !IsEditableState() )
3172             return sal_False;
3173 
3174         SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
3175 
3176         // translate positions
3177         sal_uInt16 nStart, nEnd;
3178         sal_Bool bSuccess = GetPortionData().GetEditableRange(
3179                                         nStartIndex, nEndIndex, nStart, nEnd );
3180 
3181         // edit only if the range is editable
3182         if( bSuccess )
3183         {
3184             // create SwPosition for nStartIndex
3185             SwIndex aIndex( pNode, nStart );
3186             SwPosition aStartPos( *pNode, aIndex );
3187 
3188             // create SwPosition for nEndIndex
3189             SwPosition aEndPos( aStartPos );
3190             aEndPos.nContent = nEnd;
3191 
3192             // now create XTextRange as helper and set string
3193             const uno::Reference<text::XTextRange> xRange(
3194                 SwXTextRange::CreateXTextRange(
3195                     *pNode->GetDoc(), aStartPos, &aEndPos));
3196             xRange->setString(sReplacement);
3197 
3198             // delete portion data
3199             ClearPortionData();
3200         }
3201 
3202         return bSuccess;
3203     }
3204     else
3205         throw lang::IndexOutOfBoundsException();
3206 }
3207 
3208 
3209 sal_Bool SwAccessibleParagraph::setAttributes(
3210     sal_Int32 nStartIndex,
3211     sal_Int32 nEndIndex,
3212     const uno::Sequence<PropertyValue>& rAttributeSet )
3213     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3214 {
3215     vos::OGuard aGuard(Application::GetSolarMutex());
3216     CHECK_FOR_DEFUNC( XAccessibleEditableText );
3217 
3218     const ::rtl::OUString& rText = GetString();
3219 
3220     if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
3221         throw lang::IndexOutOfBoundsException();
3222 
3223     if( !IsEditableState() )
3224         return sal_False;
3225 
3226 
3227     // create a (dummy) text portion for the sole purpose of calling
3228     // setPropertyValue on it
3229     uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
3230                                                               nEndIndex );
3231 
3232     // build sorted index array
3233     sal_Int32 nLength = rAttributeSet.getLength();
3234     const PropertyValue* pPairs = rAttributeSet.getConstArray();
3235     sal_Int32* pIndices = new sal_Int32[nLength];
3236     sal_Int32 i;
3237     for( i = 0; i < nLength; i++ )
3238         pIndices[i] = i;
3239     sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
3240 
3241     // create sorted sequences accoring to index array
3242     uno::Sequence< ::rtl::OUString > aNames( nLength );
3243     ::rtl::OUString* pNames = aNames.getArray();
3244     uno::Sequence< uno::Any > aValues( nLength );
3245     uno::Any* pValues = aValues.getArray();
3246     for( i = 0; i < nLength; i++ )
3247     {
3248         const PropertyValue& rVal = pPairs[pIndices[i]];
3249         pNames[i]  = rVal.Name;
3250         pValues[i] = rVal.Value;
3251     }
3252     delete[] pIndices;
3253 
3254     // now set the values
3255     sal_Bool bRet = sal_True;
3256     try
3257     {
3258         xPortion->setPropertyValues( aNames, aValues );
3259     }
3260     catch( UnknownPropertyException e )
3261     {
3262         // error handling through return code!
3263         bRet = sal_False;
3264     }
3265 
3266     return bRet;
3267 }
3268 
3269 sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText )
3270     throw (uno::RuntimeException)
3271 {
3272     return replaceText(0, GetString().getLength(), sText);
3273 }
3274 
3275 //=====  XAccessibleSelection  ============================================
3276 
3277 void SwAccessibleParagraph::selectAccessibleChild(
3278     sal_Int32 nChildIndex )
3279     throw ( lang::IndexOutOfBoundsException,
3280             uno::RuntimeException )
3281 {
3282     CHECK_FOR_DEFUNC( XAccessibleSelection );
3283 
3284     aSelectionHelper.selectAccessibleChild(nChildIndex);
3285 }
3286 
3287 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
3288     sal_Int32 nChildIndex )
3289     throw ( lang::IndexOutOfBoundsException,
3290             uno::RuntimeException )
3291 {
3292     CHECK_FOR_DEFUNC( XAccessibleSelection );
3293 
3294     return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
3295 }
3296 
3297 void SwAccessibleParagraph::clearAccessibleSelection(  )
3298     throw ( uno::RuntimeException )
3299 {
3300     CHECK_FOR_DEFUNC( XAccessibleSelection );
3301 
3302     aSelectionHelper.clearAccessibleSelection();
3303 }
3304 
3305 void SwAccessibleParagraph::selectAllAccessibleChildren(  )
3306     throw ( uno::RuntimeException )
3307 {
3308     CHECK_FOR_DEFUNC( XAccessibleSelection );
3309 
3310     aSelectionHelper.selectAllAccessibleChildren();
3311 }
3312 
3313 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount(  )
3314     throw ( uno::RuntimeException )
3315 {
3316     CHECK_FOR_DEFUNC( XAccessibleSelection );
3317 
3318     return aSelectionHelper.getSelectedAccessibleChildCount();
3319 }
3320 
3321 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
3322     sal_Int32 nSelectedChildIndex )
3323     throw ( lang::IndexOutOfBoundsException,
3324             uno::RuntimeException)
3325 {
3326     CHECK_FOR_DEFUNC( XAccessibleSelection );
3327 
3328     return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
3329 }
3330 
3331 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
3332 void SwAccessibleParagraph::deselectAccessibleChild(
3333     sal_Int32 nChildIndex )
3334     throw ( lang::IndexOutOfBoundsException,
3335             uno::RuntimeException )
3336 {
3337     CHECK_FOR_DEFUNC( XAccessibleSelection );
3338 
3339     aSelectionHelper.deselectAccessibleChild( nChildIndex );
3340 }
3341 
3342 //=====  XAccessibleHypertext  ============================================
3343 
3344 class SwHyperlinkIter_Impl
3345 {
3346     const SwpHints *pHints;
3347     xub_StrLen nStt;
3348     xub_StrLen nEnd;
3349     sal_uInt16 nPos;
3350 
3351 public:
3352     SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm );
3353     const SwTxtAttr *next();
3354     sal_uInt16 getCurrHintPos() const { return nPos-1; }
3355 
3356     xub_StrLen startIdx() const { return nStt; }
3357     xub_StrLen endIdx() const { return nEnd; }
3358 };
3359 
3360 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) :
3361     pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ),
3362     nStt( pTxtFrm->GetOfst() ),
3363     nPos( 0 )
3364 {
3365     const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow();
3366     nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len();
3367 }
3368 
3369 const SwTxtAttr *SwHyperlinkIter_Impl::next()
3370 {
3371     const SwTxtAttr *pAttr = 0;
3372     if( pHints )
3373     {
3374         while( !pAttr && nPos < pHints->Count() )
3375         {
3376             const SwTxtAttr *pHt = (*pHints)[nPos];
3377             if( RES_TXTATR_INETFMT == pHt->Which() )
3378             {
3379                 xub_StrLen nHtStt = *pHt->GetStart();
3380                 xub_StrLen nHtEnd = *pHt->GetAnyEnd();
3381                 if( nHtEnd > nHtStt &&
3382                     ( (nHtStt >= nStt && nHtStt < nEnd) ||
3383                       (nHtEnd > nStt && nHtEnd <= nEnd) ) )
3384                 {
3385                     pAttr = pHt;
3386                 }
3387             }
3388             ++nPos;
3389         }
3390     }
3391 
3392     return pAttr;
3393 };
3394 
3395 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
3396     throw (uno::RuntimeException)
3397 {
3398     vos::OGuard aGuard(Application::GetSolarMutex());
3399 
3400     CHECK_FOR_DEFUNC( XAccessibleHypertext );
3401 
3402     sal_Int32 nCount = 0;
3403     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
3404 //    if( !IsEditableState() )
3405     // <--
3406     {
3407         const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3408         SwHyperlinkIter_Impl aIter( pTxtFrm );
3409         while( aIter.next() )
3410             nCount++;
3411     }
3412 
3413     /* Can't fin the function "GetTOCFirstWordEndIndex" declaration in sym2.0 (Added by yanjun)
3414     if( GetTOXSortTabBase()  )
3415     {
3416         SwTxtNode* pNode = const_cast<SwTxtNode*>(GetTxtNode());
3417         if(pNode && pNode->GetTOCFirstWordEndIndex() > 0)
3418             nCount++;
3419     }
3420     */
3421     return nCount;
3422 }
3423 
3424 uno::Reference< XAccessibleHyperlink > SAL_CALL
3425     SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
3426     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3427 {
3428     vos::OGuard aGuard(Application::GetSolarMutex());
3429     CHECK_FOR_DEFUNC( XAccessibleHypertext );
3430 
3431     uno::Reference< XAccessibleHyperlink > xRet;
3432 
3433     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
3434 //    if( !IsEditableState() )
3435     const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3436     SwHyperlinkIter_Impl aHIter( pTxtFrm );
3437     //SwAccessibleAutoRecognizerHelper_Impl aARHelper( pTxtFrm );
3438     sal_Int32 nARCount = 0;
3439     sal_Int32 nARIndex = 0;
3440     sal_Int32 nTIndex = -1;
3441     sal_Int32 nTOCEndIndex = -1;
3442     SwTxtNode* pNode = NULL;
3443     SwTOXSortTabBase* pTBase = GetTOXSortTabBase();
3444     if( pTBase )
3445     {
3446         pNode = const_cast<SwTxtNode*>(GetTxtNode());
3447     }
3448     nTOCEndIndex = -1;
3449     //if(pNode)
3450     //  nTOCEndIndex = pNode->GetTOCFirstWordEndIndex();
3451     SwTxtAttr* pHt = (SwTxtAttr*)(aHIter.next());
3452     while( (nLinkIndex < getHyperLinkCount()) && nTIndex < nLinkIndex)
3453     {
3454         // no candidates, exit
3455         //if( (!pHt) && (nARIndex >= nARCount) && nTOCEndIndex <= 0)
3456         //  break;
3457 
3458         sal_Int32 nHStt = -1;
3459         sal_Int32 nAStt = -1;
3460         sal_Bool bH = sal_False;
3461         sal_Bool bA = sal_False;
3462 
3463 
3464         if( pHt )
3465             nHStt = *pHt->GetStart();
3466         if( nARIndex < nARCount )
3467         {
3468             /*
3469             sal_Int32 nAEnd;
3470             aARHelper.getPosition( nARIndex, nAStt, nAEnd );
3471             */
3472         }
3473         sal_Bool bTOC = sal_False;
3474         // Inside TOC & get the first link
3475         if( pTBase && nTIndex == -1 )
3476         {
3477             nTIndex++;
3478             bTOC = sal_True;
3479         }
3480         else
3481         {
3482             if( nHStt >=0 && nAStt >=0 )
3483             {   // both hyperlink and smart tag available
3484                 nTIndex++;
3485                 if( nHStt <= nAStt )
3486                     bH = sal_True;
3487                 else
3488                     bA = sal_True;
3489             }
3490             else if( nHStt >= 0 )
3491             {   // only hyperlink available
3492                 nTIndex++;
3493                 bH = sal_True;
3494             }
3495             else if( nAStt >= 0 )
3496             {   // only smart tag available
3497                 nTIndex++;
3498                 bA = sal_True;
3499             }
3500         }
3501 
3502         if( nTIndex == nLinkIndex )
3503         {   // found
3504             if( bH )
3505             {   // it's a hyperlink
3506                 if( pHt )
3507                 {
3508 //                    const SwField* pFFld = pHt->GetFld().GetFld();
3509                     {
3510                         if( !pHyperTextData )
3511                             pHyperTextData = new SwAccessibleHyperTextData;
3512                         SwAccessibleHyperTextData::iterator aIter =
3513                             pHyperTextData ->find( pHt );
3514                         if( aIter != pHyperTextData->end() )
3515                         {
3516                             xRet = (*aIter).second;
3517                         }
3518                         if( !xRet.is() )
3519                         {
3520                             {
3521                                 const sal_Int32 nTmpHStt= GetPortionData().GetAccessiblePosition(
3522                                     max( aHIter.startIdx(), *pHt->GetStart() ) );
3523                                 const sal_Int32 nTmpHEnd= GetPortionData().GetAccessiblePosition(
3524                                     min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
3525                                 xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
3526                                     this, nTmpHStt, nTmpHEnd );
3527                             }
3528                             if( aIter != pHyperTextData->end() )
3529                             {
3530                                 (*aIter).second = xRet;
3531                             }
3532                             else
3533                             {
3534                                 SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
3535                                 pHyperTextData->insert( aEntry );
3536                             }
3537                         }
3538                     }
3539                 }
3540             }
3541             else if( bTOC )
3542             {
3543                 //xRet = new SwAccessibleTOCLink( this );
3544             }
3545             else if( bA )
3546             {
3547                 /*
3548                 // it's a smart tag
3549                 if( !pAutoRecognizerData )
3550                     pAutoRecognizerData = new SwAccessibleAutoRecognizerData;
3551                 SwAccessibleAutoRecognizerData::iterator aIter =
3552                     pAutoRecognizerData ->find( nARIndex );
3553                 if( aIter != pAutoRecognizerData->end() )
3554                 {
3555                     xRet = (*aIter).second;
3556                 }
3557                 if( !xRet.is() )
3558                 {
3559                     sal_Int32 nAStt = 0;
3560                     sal_Int32 nAEnd = 0;
3561                     //aARHelper.getPosition( nARIndex, nAStt, nAEnd );
3562                     xRet = new SwAccessibleAutoRecognizer( this, nAStt, nAEnd );
3563                     if( aIter != pAutoRecognizerData->end() )
3564                     {
3565                         (*aIter).second = xRet;
3566                     }
3567                     else
3568                     {
3569                         SwAccessibleAutoRecognizerData::value_type aEntry( nARIndex, xRet );
3570                         pAutoRecognizerData->insert( aEntry );
3571                     }
3572                 }
3573                 */
3574             }
3575             break;
3576         }
3577 
3578         // iterate next
3579         if( bH )
3580             // iterate next hyperlink
3581             pHt = (SwTxtAttr*)(aHIter.next());
3582         else if( bA )
3583             // iterate next smart tag
3584             nARIndex++;
3585         else if(bTOC)
3586             continue;
3587         else
3588             // no candidate, exit
3589             break;
3590     }
3591     /*
3592         const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3593         SwHyperlinkIter_Impl aHIter( pTxtFrm );
3594         while( nLinkIndex-- )
3595             aHIter.next();
3596 
3597         const SwTxtAttr *pHt = aHIter.next();
3598         if( pHt )
3599         {
3600             if( !pHyperTextData )
3601                 pHyperTextData = new SwAccessibleHyperTextData;
3602             SwAccessibleHyperTextData::iterator aIter =
3603                 pHyperTextData ->find( pHt );
3604             if( aIter != pHyperTextData->end() )
3605             {
3606                 xRet = (*aIter).second;
3607             }
3608             if( !xRet.is() )
3609             {
3610                 sal_Int32 nHStt= GetPortionData().GetAccessiblePosition(
3611                                 max( aHIter.startIdx(), *pHt->GetStart() ) );
3612                 sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition(
3613                                 min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
3614                 xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
3615                                                   this, nHStt, nHEnd );
3616                 if( aIter != pHyperTextData->end() )
3617                 {
3618                     (*aIter).second = xRet;
3619                 }
3620                 else
3621                 {
3622                     SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
3623                     pHyperTextData->insert( aEntry );
3624                 }
3625             }
3626         }
3627     }
3628     */
3629     if( !xRet.is() )
3630         throw lang::IndexOutOfBoundsException();
3631 
3632     return xRet;
3633 }
3634 
3635 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
3636     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
3637 {
3638     vos::OGuard aGuard(Application::GetSolarMutex());
3639     CHECK_FOR_DEFUNC( XAccessibleHypertext );
3640 
3641     // parameter checking
3642     sal_Int32 nLength = GetString().getLength();
3643     if ( ! IsValidPosition( nCharIndex, nLength ) )
3644     {
3645         throw lang::IndexOutOfBoundsException();
3646     }
3647 
3648     sal_Int32 nRet = -1;
3649     // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
3650 //    if( !IsEditableState() )
3651     // <--
3652     {
3653         const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
3654         SwHyperlinkIter_Impl aHIter( pTxtFrm );
3655 
3656         xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex );
3657         sal_Int32 nPos = 0;
3658         const SwTxtAttr *pHt = aHIter.next();
3659         while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) )
3660         {
3661             pHt = aHIter.next();
3662             nPos++;
3663         }
3664 
3665         if( pHt )
3666             nRet = nPos;
3667     }
3668     /* Added by yanjun for acc miagration
3669     if( nRet == -1 && GetTOXSortTabBase() )
3670     {
3671         SwTxtNode* pNode = const_cast<SwTxtNode*>(GetTxtNode());
3672         if( nCharIndex >= 0 && nCharIndex < pNode->GetTOCFirstWordEndIndex())
3673             nRet = 0;
3674     }
3675     */
3676 
3677     if (nRet == -1)
3678         throw lang::IndexOutOfBoundsException();
3679     else
3680         return nRet;
3681     //return nRet;
3682 }
3683 
3684 // --> OD 2008-05-26 #i71360#
3685 // --> OD 2010-02-22 #i108125# - adjustments for change tracking text markup
3686 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
3687                                         throw (lang::IllegalArgumentException,
3688                                                uno::RuntimeException)
3689 {
3690     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3691     switch ( nTextMarkupType )
3692     {
3693         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3694         case text::TextMarkupType::TRACK_CHANGE_DELETION:
3695         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3696         {
3697             pTextMarkupHelper.reset( new SwTextMarkupHelper(
3698                 GetPortionData(),
3699                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3700         }
3701         break;
3702         default:
3703         {
3704             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
3705         }
3706     }
3707 
3708     return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType );
3709 }
3710 //MSAA Extension Implementation in app  module
3711 sal_Bool SAL_CALL SwAccessibleParagraph::scrollToPosition( const ::com::sun::star::awt::Point&, sal_Bool )
3712     throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
3713 {
3714     return sal_False;
3715 }
3716 
3717 sal_Int32 SAL_CALL SwAccessibleParagraph::getSelectedPortionCount(  )
3718     throw (::com::sun::star::uno::RuntimeException)
3719 {
3720     sal_Int32 nSeleted = 0;
3721     SwPaM* pCrsr = GetCursor( true );
3722     if( pCrsr != NULL )
3723     {
3724         // get SwPosition for my node
3725         const SwTxtNode* pNode = GetTxtNode();
3726         sal_uLong nHere = pNode->GetIndex();
3727 
3728         // iterate over ring
3729         SwPaM* pRingStart = pCrsr;
3730         do
3731         {
3732             // ignore, if no mark
3733             if( pCrsr->HasMark() )
3734             {
3735                 // check whether nHere is 'inside' pCrsr
3736                 SwPosition* pStart = pCrsr->Start();
3737                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3738                 SwPosition* pEnd = pCrsr->End();
3739                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3740                 if( ( nHere >= nStartIndex ) &&
3741                     ( nHere <= nEndIndex )      )
3742                 {
3743                     nSeleted++;
3744                 }
3745                 // else: this PaM doesn't point to this paragraph
3746             }
3747             // else: this PaM is collapsed and doesn't select anything
3748 
3749             // next PaM in ring
3750             pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
3751         }
3752         while( pCrsr != pRingStart );
3753     }
3754     return nSeleted;
3755 
3756 }
3757 
3758 sal_Int32 SAL_CALL SwAccessibleParagraph::getSeletedPositionStart( sal_Int32 nSelectedPortionIndex )
3759     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3760 {
3761     vos::OGuard aGuard(Application::GetSolarMutex());
3762 
3763     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3764 
3765     sal_Int32 nStart, nEnd;
3766     /*sal_Bool bSelected = */GetSelectionAtIndex(nSelectedPortionIndex, nStart, nEnd );
3767     return nStart;
3768 }
3769 
3770 sal_Int32 SAL_CALL SwAccessibleParagraph::getSeletedPositionEnd( sal_Int32 nSelectedPortionIndex )
3771     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3772 {
3773     vos::OGuard aGuard(Application::GetSolarMutex());
3774 
3775     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3776 
3777     sal_Int32 nStart, nEnd;
3778     /*sal_Bool bSelected = */GetSelectionAtIndex(nSelectedPortionIndex, nStart, nEnd );
3779     return nEnd;
3780 }
3781 
3782 sal_Bool SAL_CALL SwAccessibleParagraph::removeSelection( sal_Int32 selectionIndex )
3783     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3784 {
3785     if(selectionIndex < 0) return sal_False;
3786 
3787     sal_Bool bRet = sal_False;
3788     sal_Int32 nSelected = selectionIndex;
3789 
3790     // get the selection, and test whether it affects our text node
3791     SwPaM* pCrsr = GetCursor( true );
3792 //  SwPaM* pFirst = pCrsr;
3793     SwPaM* pPrev = pCrsr;
3794 
3795     if( pCrsr != NULL )
3796     {
3797         // get SwPosition for my node
3798         const SwTxtNode* pNode = GetTxtNode();
3799         sal_uLong nHere = pNode->GetIndex();
3800 
3801         // iterate over ring
3802         SwPaM* pRingStart = pCrsr;
3803         do
3804         {
3805             // ignore, if no mark
3806             if( pCrsr->HasMark() )
3807             {
3808                 // check whether nHere is 'inside' pCrsr
3809                 SwPosition* pStart = pCrsr->Start();
3810                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3811                 SwPosition* pEnd = pCrsr->End();
3812                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3813                 if( ( nHere >= nStartIndex ) &&
3814                     ( nHere <= nEndIndex )      )
3815                 {
3816                     if( nSelected == 0 )
3817                     {
3818                         pCrsr->MoveTo((Ring*)0);
3819                         delete pCrsr;
3820                         bRet = sal_True;
3821                     }
3822                     else
3823                     {
3824                         nSelected--;
3825                     }
3826                 }
3827             }
3828             // else: this PaM is collapsed and doesn't select anything
3829            pPrev = pCrsr;
3830            pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
3831         }
3832         while( !bRet && (pCrsr != pRingStart) );
3833     }
3834     return sal_True;
3835 }
3836 
3837 sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection( sal_Int32, sal_Int32 startOffset, sal_Int32 endOffset)
3838     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
3839 {
3840     vos::OGuard aGuard(Application::GetSolarMutex());
3841 
3842     CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
3843 
3844     // parameter checking
3845     sal_Int32 nLength = GetString().getLength();
3846     if ( ! IsValidRange( startOffset, endOffset, nLength ) )
3847     {
3848         throw lang::IndexOutOfBoundsException();
3849     }
3850 
3851     sal_Int32 nSelectedCount = getSelectedPortionCount();
3852     for ( sal_Int32 i = nSelectedCount ; i >= 0 ; i--)
3853     {
3854         sal_Int32 nStart, nEnd;
3855         sal_Bool bSelected = GetSelectionAtIndex(i, nStart, nEnd );
3856         if(bSelected)
3857         {
3858             if(nStart <= nEnd )
3859             {
3860                 if (( startOffset>=nStart && startOffset <=nEnd ) ||     //startOffset in a selection
3861                     ( endOffset>=nStart && endOffset <=nEnd )     ||  //endOffset in a selection
3862                     ( startOffset <= nStart && endOffset >=nEnd)  ||       //start and  end include the old selection
3863                     ( startOffset >= nStart && endOffset <=nEnd) )
3864                 {
3865                     removeSelection(i);
3866                 }
3867 
3868             }
3869             else
3870             {
3871                 if (( startOffset>=nEnd && startOffset <=nStart ) ||     //startOffset in a selection
3872                     ( endOffset>=nEnd && endOffset <=nStart )     || //endOffset in a selection
3873                     ( startOffset <= nStart && endOffset >=nEnd)  ||       //start and  end include the old selection
3874                     ( startOffset >= nStart && endOffset <=nEnd) )
3875 
3876                 {
3877                     removeSelection(i);
3878                 }
3879             }
3880         }
3881 
3882     }
3883 
3884     sal_Bool bRet = sal_False;
3885 
3886     // get cursor shell
3887     SwCrsrShell* pCrsrShell = GetCrsrShell();
3888     if( pCrsrShell != NULL )
3889     {
3890         // create pam for selection
3891         pCrsrShell->StartAction();
3892 //        SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
3893         SwPaM* aPaM = pCrsrShell->CreateCrsr();
3894         aPaM->SetMark();
3895         aPaM->GetPoint()->nContent = GetPortionData().GetModelPosition(startOffset);
3896         aPaM->GetMark()->nContent =  GetPortionData().GetModelPosition(endOffset);
3897         //pCrsrShell->ShowCrsr();
3898         pCrsrShell->EndAction();
3899         // set PaM at cursor shell
3900         //bRet = Select( aPaM );
3901     }
3902 
3903     return bRet;
3904 }
3905 
3906 /*accessibility::*/TextSegment SAL_CALL
3907         SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
3908                                               sal_Int32 nTextMarkupType )
3909                                         throw (lang::IndexOutOfBoundsException,
3910                                                lang::IllegalArgumentException,
3911                                                uno::RuntimeException)
3912 {
3913     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3914     switch ( nTextMarkupType )
3915     {
3916         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3917         case text::TextMarkupType::TRACK_CHANGE_DELETION:
3918         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3919         {
3920             pTextMarkupHelper.reset( new SwTextMarkupHelper(
3921                 GetPortionData(),
3922                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3923         }
3924         break;
3925         default:
3926         {
3927             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
3928         }
3929     }
3930 
3931     return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
3932 }
3933 
3934 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
3935         SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
3936                                                      sal_Int32 nTextMarkupType )
3937                                         throw (lang::IndexOutOfBoundsException,
3938                                                lang::IllegalArgumentException,
3939                                                uno::RuntimeException)
3940 {
3941     // parameter checking
3942     const sal_Int32 nLength = GetString().getLength();
3943     if ( ! IsValidPosition( nCharIndex, nLength ) )
3944     {
3945         throw lang::IndexOutOfBoundsException();
3946     }
3947 
3948     std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3949     switch ( nTextMarkupType )
3950     {
3951         case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3952         case text::TextMarkupType::TRACK_CHANGE_DELETION:
3953         case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3954         {
3955             pTextMarkupHelper.reset( new SwTextMarkupHelper(
3956                 GetPortionData(),
3957                 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3958         }
3959         break;
3960         default:
3961         {
3962             pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
3963         }
3964     }
3965 
3966     return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
3967 }
3968 // <--
3969 
3970 // --> OD 2008-05-29 #i89175#
3971 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
3972                                         throw (lang::IndexOutOfBoundsException,
3973                                                uno::RuntimeException)
3974 {
3975     // parameter checking
3976     const sal_Int32 nLength = GetString().getLength();
3977     if ( ! IsValidPosition( nIndex, nLength ) )
3978     {
3979         throw lang::IndexOutOfBoundsException();
3980     }
3981 
3982     const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
3983     return nLineNo;
3984 }
3985 
3986 /*accessibility::*/TextSegment SAL_CALL
3987         SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
3988                                         throw (lang::IndexOutOfBoundsException,
3989                                                uno::RuntimeException)
3990 {
3991     // parameter checking
3992     if ( nLineNo < 0 ||
3993          nLineNo >= GetPortionData().GetLineCount() )
3994     {
3995         throw lang::IndexOutOfBoundsException();
3996     }
3997 
3998     i18n::Boundary aLineBound;
3999     GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
4000 
4001     /*accessibility::*/TextSegment aTextAtLine;
4002     const ::rtl::OUString rText = GetString();
4003     aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
4004                                           aLineBound.endPos - aLineBound.startPos );
4005     aTextAtLine.SegmentStart = aLineBound.startPos;
4006     aTextAtLine.SegmentEnd = aLineBound.endPos;
4007 
4008     return aTextAtLine;
4009 }
4010 
4011 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
4012                                         throw (uno::RuntimeException)
4013 {
4014     const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
4015 
4016     if ( nLineNoOfCaret >= 0 &&
4017          nLineNoOfCaret < GetPortionData().GetLineCount() )
4018     {
4019         return getTextAtLineNumber( nLineNoOfCaret );
4020     }
4021 
4022     return /*accessibility::*/TextSegment();
4023 }
4024 
4025 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
4026                                         throw (uno::RuntimeException)
4027 {
4028     const sal_Int32 nCaretPos = getCaretPosition();
4029     const sal_Int32 nLength = GetString().getLength();
4030     if ( !IsValidPosition( nCaretPos, nLength ) )
4031     {
4032         return -1;
4033     }
4034 
4035     sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
4036 
4037     // special handling for cursor positioned at end of text line via End key
4038     if ( nCaretPos != 0 )
4039     {
4040         i18n::Boundary aLineBound;
4041         GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
4042         if ( nCaretPos == aLineBound.startPos )
4043         {
4044             SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
4045             if ( pCrsrShell != 0 )
4046             {
4047                 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
4048 
4049                 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect();
4050                 // translate core coordinates into accessibility coordinates
4051                 Window *pWin = GetWindow();
4052                 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
4053 
4054                 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
4055 
4056                 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
4057                 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
4058                 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
4059 
4060                 // convert into AWT Rectangle
4061                 const awt::Rectangle aCursorRect( aScreenRect.Left(),
4062                                                   aScreenRect.Top(),
4063                                                   aScreenRect.GetWidth(),
4064                                                   aScreenRect.GetHeight() );
4065 
4066                 if ( aCharRect.X != aCursorRect.X ||
4067                      aCharRect.Y != aCursorRect.Y )
4068                 {
4069                     --nLineNo;
4070                 }
4071             }
4072         }
4073     }
4074 
4075     return nLineNo;
4076 }
4077 
4078 // --> OD 2010-02-19 #i108125#
4079 void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
4080 {
4081     mpParaChangeTrackInfo->reset();
4082 
4083     CheckRegistration( pOld, pNew );
4084 }
4085 // <--
4086 
4087 sal_Bool SwAccessibleParagraph::GetSelectionAtIndex(
4088     sal_Int32& nIndex, sal_Int32& nStart, sal_Int32& nEnd)
4089 {
4090         if(nIndex < 0) return sal_False;
4091 
4092 
4093     sal_Bool bRet = sal_False;
4094     nStart = -1;
4095     nEnd = -1;
4096     sal_Int32 nSelected = nIndex;
4097 
4098     // get the selection, and test whether it affects our text node
4099     SwPaM* pCrsr = GetCursor( true );
4100     if( pCrsr != NULL )
4101     {
4102         // get SwPosition for my node
4103         const SwTxtNode* pNode = GetTxtNode();
4104         sal_uLong nHere = pNode->GetIndex();
4105 
4106         // iterate over ring
4107         SwPaM* pRingStart = pCrsr;
4108         do
4109         {
4110             // ignore, if no mark
4111             if( pCrsr->HasMark() )
4112             {
4113                 // check whether nHere is 'inside' pCrsr
4114                 SwPosition* pStart = pCrsr->Start();
4115                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
4116                 SwPosition* pEnd = pCrsr->End();
4117                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
4118                 if( ( nHere >= nStartIndex ) &&
4119                     ( nHere <= nEndIndex )      )
4120                 {
4121                     if( nSelected == 0 )
4122                     {
4123                         // translate start and end positions
4124 
4125                         // start position
4126                         sal_Int32 nLocalStart = -1;
4127                         if( nHere > nStartIndex )
4128                         {
4129                             // selection starts in previous node:
4130                             // then our local selection starts with the paragraph
4131                             nLocalStart = 0;
4132                         }
4133                         else
4134                         {
4135                             DBG_ASSERT( nHere == nStartIndex,
4136                                         "miscalculated index" );
4137 
4138                             // selection starts in this node:
4139                             // then check whether it's before or inside our part of
4140                             // the paragraph, and if so, get the proper position
4141                             sal_uInt16 nCoreStart = pStart->nContent.GetIndex();
4142                             if( nCoreStart <
4143                                 GetPortionData().GetFirstValidCorePosition() )
4144                             {
4145                                 nLocalStart = 0;
4146                             }
4147                             else if( nCoreStart <=
4148                                      GetPortionData().GetLastValidCorePosition() )
4149                             {
4150                                 DBG_ASSERT(
4151                                     GetPortionData().IsValidCorePosition(
4152                                                                       nCoreStart ),
4153                                      "problem determining valid core position" );
4154 
4155                                 nLocalStart =
4156                                     GetPortionData().GetAccessiblePosition(
4157                                                                       nCoreStart );
4158                             }
4159                         }
4160 
4161                         // end position
4162                         sal_Int32 nLocalEnd = -1;
4163                         if( nHere < nEndIndex )
4164                         {
4165                             // selection ends in following node:
4166                             // then our local selection extends to the end
4167                             nLocalEnd = GetPortionData().GetAccessibleString().
4168                                                                        getLength();
4169                         }
4170                         else
4171                         {
4172                             DBG_ASSERT( nHere == nStartIndex,
4173                                         "miscalculated index" );
4174 
4175                             // selection ends in this node: then select everything
4176                             // before our part of the node
4177                             sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex();
4178                             if( nCoreEnd >
4179                                     GetPortionData().GetLastValidCorePosition() )
4180                             {
4181                                 // selection extends beyond out part of this para
4182                                 nLocalEnd = GetPortionData().GetAccessibleString().
4183                                                                        getLength();
4184                             }
4185                             else if( nCoreEnd >=
4186                                      GetPortionData().GetFirstValidCorePosition() )
4187                             {
4188                                 // selection is inside our part of this para
4189                                 DBG_ASSERT(
4190                                     GetPortionData().IsValidCorePosition(
4191                                                                       nCoreEnd ),
4192                                      "problem determining valid core position" );
4193 
4194                                 nLocalEnd = GetPortionData().GetAccessiblePosition(
4195                                                                        nCoreEnd );
4196                             }
4197                         }
4198 
4199                         if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
4200                         {
4201                             nStart = nLocalStart;
4202                             nEnd = nLocalEnd;
4203                             bRet = sal_True;
4204                         }
4205                     } // if hit the index
4206                     else
4207                     {
4208                         nSelected--;
4209                     }
4210                 }
4211                 // else: this PaM doesn't point to this paragraph
4212             }
4213             // else: this PaM is collapsed and doesn't select anything
4214 
4215             // next PaM in ring
4216             pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
4217         }
4218         while( !bRet && (pCrsr != pRingStart) );
4219     }
4220     // else: nocursor -> no selection
4221 
4222     if( bRet )
4223     {
4224         sal_Int32 nCaretPos = GetCaretPos();
4225         if( nStart == nCaretPos )
4226         {
4227             sal_Int32 tmp = nStart;
4228             nStart = nEnd;
4229             nEnd = tmp;
4230         }
4231     }
4232     return bRet;
4233 }
4234 
4235 sal_Int16 SAL_CALL SwAccessibleParagraph::getAccessibleRole (void) throw (::com::sun::star::uno::RuntimeException)
4236 {
4237     //Get the real heading level, Heading1 ~ Heading10
4238     if (nHeadingLevel > 0)
4239     {
4240         return AccessibleRole::HEADING;
4241     }
4242     else
4243     {
4244         return AccessibleRole::PARAGRAPH;
4245     }
4246 }
4247 
4248 // End Add
4249 
4250 
4251 /* This funcion is already defined in accpara.cxx(Added by yanjun)
4252 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
4253         throw (::com::sun::star::uno::RuntimeException)
4254 {
4255 // Test Code
4256 //     Sequence<OUString> seNames(1);
4257 //     OUString* pStrings = seNames.getArray();
4258 //  pStrings[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("ParaBackColor"));
4259 //
4260 //     Sequence<Any> aAnys(1);
4261 //  Reference<XMultiPropertySet> xPortion = CreateUnoPortion( 0, 0 );
4262 //     aAnys = xPortion->getPropertyValues( seNames );
4263 //  const Any* pAnys = aAnys.getConstArray();
4264 //
4265 //  sal_uInt32 crColorT=0;
4266 //  pAnys[0] >>= crColorT;
4267 // End Test Code
4268 
4269     const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground();
4270     sal_uInt32 crBack = rBack.GetColor().GetColor();
4271 
4272     if (COL_AUTO == crBack)
4273     {
4274         Reference<XAccessible> xAccDoc = getAccessibleParent();
4275         if (xAccDoc.is())
4276         {
4277             Reference<XAccessibleComponent> xCompoentDoc(xAccDoc,UNO_QUERY);
4278             if (xCompoentDoc.is())
4279             {
4280                 crBack = (sal_uInt32)xCompoentDoc->getBackground();
4281             }
4282         }
4283     }
4284     return crBack;
4285 }
4286 */
4287 
4288 //Get the real heading level, Heading1 ~ Heading10
4289 sal_Int32 SwAccessibleParagraph::GetRealHeadingLevel()
4290 {
4291     uno::Reference< ::com::sun::star::beans::XPropertySet > xPortion = CreateUnoPortion( 0, 0 );
4292     ::rtl::OUString pString = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaStyleName"));
4293     uno::Any styleAny = xPortion->getPropertyValue( pString );
4294     ::rtl::OUString sValue;
4295     if (styleAny >>= sValue)
4296     {
4297         //Modified by yanjun for acc migration
4298         sal_Int32 length = sValue.getLength/*GetCharCount*/();
4299         if (length == 9 || length == 10)
4300         {
4301             ::rtl::OUString headStr = sValue.copy(0, 7);
4302             if (headStr.equals(::rtl::OUString::createFromAscii("Heading")))
4303             {
4304                 ::rtl::OUString intStr = sValue.copy(8);
4305                 sal_Int32 headingLevel = intStr.toInt32(10);
4306                 return headingLevel;
4307             }
4308         }
4309     }
4310     return -1;
4311 }
4312 
4313 uno::Any SAL_CALL SwAccessibleParagraph::getExtendedAttributes()
4314         throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
4315 {
4316     uno::Any Ret;
4317     ::rtl::OUString strHeading(::rtl::OUString::createFromAscii("heading-level:"));
4318     if( nHeadingLevel >= 0 )
4319         strHeading += OUString::valueOf(nHeadingLevel, 10);
4320     strHeading += OUString::createFromAscii(";");
4321 
4322     Ret <<= strHeading;
4323 
4324     return Ret;
4325 }
4326 
4327 //Tab will be return when call WORDTYPE
4328 sal_Bool SwAccessibleParagraph::tabCharInWord( sal_Int32 nIndex, i18n::Boundary& aBound)
4329 {
4330     sal_Bool bFind =  sal_False;
4331     if( aBound.startPos != nIndex)
4332     {
4333         OUString tabStr;
4334         if(aBound.startPos>nIndex)
4335             tabStr = GetString().copy(nIndex,(aBound.startPos - nIndex) );
4336 
4337         sal_Unicode tabChar('\t');
4338         sal_Int32 tabIndex = tabStr.indexOf(tabChar);
4339         if( tabIndex > -1 )
4340         {
4341             aBound.startPos = nIndex + tabIndex ;
4342             aBound.endPos = aBound.startPos + 1;
4343             bFind = sal_True;
4344         }
4345     }
4346     return bFind;
4347 }
4348