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