merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / access / accpara.cxx
bloba48e36d1342a4f26d70008115aaab8a9404bd8e7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accpara.cxx,v $
10 * $Revision: 1.78 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <txtfrm.hxx>
34 #include <ndtxt.hxx>
35 #include <pam.hxx>
36 #include <unoobj.hxx>
37 #include <crstate.hxx>
38 #include <accmap.hxx>
39 #include "fesh.hxx"
40 #include <viewopt.hxx>
41 #include <vos/mutex.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/window.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include <com/sun/star/accessibility/AccessibleRole.hpp>
46 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
47 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
48 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
49 #include <unotools/accessiblestatesethelper.hxx>
50 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
51 #include <com/sun/star/i18n/WordType.hpp>
52 #include <com/sun/star/i18n/XBreakIterator.hpp>
53 #include <com/sun/star/beans/UnknownPropertyException.hpp>
54 #include <breakit.hxx>
55 #include "accpara.hxx"
56 #ifndef _ACCESS_HRC
57 #include "access.hrc"
58 #endif
59 #include "accportions.hxx"
60 #include <sfx2/viewsh.hxx> // for ExecuteAtViewShell(...)
61 #include <sfx2/viewfrm.hxx> // for ExecuteAtViewShell(...)
62 #include <sfx2/dispatch.hxx> // for ExecuteAtViewShell(...)
63 #include <unotools/charclass.hxx> // for GetWordBoundary
64 // for get/setCharacterAttribute(...)
65 #include "unocrsr.hxx"
66 #include "unoobj.hxx"
67 #include "unoport.hxx"
68 #include "doc.hxx"
69 #include "crsskip.hxx"
70 #include <txtatr.hxx>
71 #include <acchyperlink.hxx>
72 #include <acchypertextdata.hxx>
73 // --> OD 2005-12-02 #i27138#
74 #include <unotools/accessiblerelationsethelper.hxx>
75 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
76 // <--
77 #include <comphelper/accessibletexthelper.hxx>
78 // --> OD 2006-07-12 #i63870#
79 #include <unomap.hxx>
80 // <--
81 // --> OD 2007-01-15 #i72800#
82 #include <unoprnms.hxx>
83 // <--
84 // --> OD 2007-01-15 #i73371#
85 #include <com/sun/star/text/WritingMode2.hpp>
86 // <--
87 // --> OD 2007-01-17 #i71385#
88 #include <svx/brshitem.hxx>
89 #include <viewimp.hxx>
90 // <--
91 // --> OD 2007-11-12 #i82637#
92 #include <boost/scoped_ptr.hpp>
93 // <--
94 // --> OD 2008-05-26 #i71360#
95 #include <textmarkuphelper.hxx>
96 // <--
98 #include <algorithm>
100 using namespace ::com::sun::star;
101 using namespace ::com::sun::star::i18n;
102 using namespace ::com::sun::star::lang;
103 using namespace ::com::sun::star::uno;
104 using namespace ::com::sun::star::accessibility;
105 using ::rtl::OUString;
107 using beans::PropertyValue;
108 using beans::XMultiPropertySet;
109 using beans::UnknownPropertyException;
110 using beans::PropertyState_DIRECT_VALUE;
112 using std::max;
113 using std::min;
114 using std::sort;
116 namespace com { namespace sun { namespace star {
117 namespace text {
118 class XText;
120 } } }
123 const sal_Char sServiceName[] = "com.sun.star.text.AccessibleParagraphView";
124 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView";
125 const xub_StrLen MAX_DESC_TEXT_LEN = 40;
126 const SwTxtNode* SwAccessibleParagraph::GetTxtNode() const
128 const SwFrm* pFrm = GetFrm();
129 DBG_ASSERT( pFrm->IsTxtFrm(), "The text frame has mutated!" );
131 const SwTxtNode* pNode = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode();
132 DBG_ASSERT( pNode != NULL, "A text frame without a text node." );
134 return pNode;
137 OUString SwAccessibleParagraph::GetString()
139 return GetPortionData().GetAccessibleString();
142 OUString SwAccessibleParagraph::GetDescription()
144 // --> OD 2004-09-29 #117933# - provide empty description for paragraphs
145 return OUString();
146 // <--
149 sal_Int32 SwAccessibleParagraph::GetCaretPos()
151 sal_Int32 nRet = -1;
153 // get the selection's point, and test whether it's in our node
154 // --> OD 2005-12-20 #i27301# - consider adjusted method signature
155 SwPaM* pCaret = GetCursor( false ); // caret is first PaM in PaM-ring
156 // <--
157 if( pCaret != NULL )
159 const SwTxtNode* pNode = GetTxtNode();
161 // check whether the point points into 'our' node
162 SwPosition* pPoint = pCaret->GetPoint();
163 if( pNode->GetIndex() == pPoint->nNode.GetIndex() )
165 // same node? Then check whether it's also within 'our' part
166 // of the paragraph
167 USHORT nIndex = pPoint->nContent.GetIndex();
168 if( GetPortionData().IsValidCorePosition( nIndex ) )
170 // Yes, it's us!
171 // --> OD 2006-10-19 #70538#
172 // consider that cursor/caret is in front of the list label
173 if ( pCaret->IsInFrontOfLabel() )
175 nRet = 0;
177 else
179 nRet = GetPortionData().GetAccessiblePosition( nIndex );
181 // <--
183 DBG_ASSERT( nRet >= 0, "invalid cursor?" );
184 DBG_ASSERT( nRet <= GetPortionData().GetAccessibleString().
185 getLength(), "invalid cursor?" );
187 // else: in this paragraph, but in different frame
189 // else: not in this paragraph
191 // else: no cursor -> no caret
193 return nRet;
196 sal_Bool SwAccessibleParagraph::GetSelection(
197 sal_Int32& nStart, sal_Int32& nEnd)
199 sal_Bool bRet = sal_False;
200 nStart = -1;
201 nEnd = -1;
203 // get the selection, and test whether it affects our text node
204 // --> OD 2005-12-20 #i27301# - consider adjusted method signature
205 SwPaM* pCrsr = GetCursor( true );
206 // <--
207 if( pCrsr != NULL )
209 // get SwPosition for my node
210 const SwTxtNode* pNode = GetTxtNode();
211 ULONG nHere = pNode->GetIndex();
213 // iterate over ring
214 SwPaM* pRingStart = pCrsr;
217 // ignore, if no mark
218 if( pCrsr->HasMark() )
220 // check whether nHere is 'inside' pCrsr
221 SwPosition* pStart = pCrsr->Start();
222 ULONG nStartIndex = pStart->nNode.GetIndex();
223 SwPosition* pEnd = pCrsr->End();
224 ULONG nEndIndex = pEnd->nNode.GetIndex();
225 if( ( nHere >= nStartIndex ) &&
226 ( nHere <= nEndIndex ) )
228 // translate start and end positions
230 // start position
231 sal_Int32 nLocalStart = -1;
232 if( nHere > nStartIndex )
234 // selection starts in previous node:
235 // then our local selection starts with the paragraph
236 nLocalStart = 0;
238 else
240 DBG_ASSERT( nHere == nStartIndex,
241 "miscalculated index" );
243 // selection starts in this node:
244 // then check whether it's before or inside our part of
245 // the paragraph, and if so, get the proper position
246 USHORT nCoreStart = pStart->nContent.GetIndex();
247 if( nCoreStart <
248 GetPortionData().GetFirstValidCorePosition() )
250 nLocalStart = 0;
252 else if( nCoreStart <=
253 GetPortionData().GetLastValidCorePosition() )
255 DBG_ASSERT(
256 GetPortionData().IsValidCorePosition(
257 nCoreStart ),
258 "problem determining valid core position" );
260 nLocalStart =
261 GetPortionData().GetAccessiblePosition(
262 nCoreStart );
266 // end position
267 sal_Int32 nLocalEnd = -1;
268 if( nHere < nEndIndex )
270 // selection ends in following node:
271 // then our local selection extends to the end
272 nLocalEnd = GetPortionData().GetAccessibleString().
273 getLength();
275 else
277 DBG_ASSERT( nHere == nEndIndex,
278 "miscalculated index" );
280 // selection ends in this node: then select everything
281 // before our part of the node
282 USHORT nCoreEnd = pEnd->nContent.GetIndex();
283 if( nCoreEnd >
284 GetPortionData().GetLastValidCorePosition() )
286 // selection extends beyond out part of this para
287 nLocalEnd = GetPortionData().GetAccessibleString().
288 getLength();
290 else if( nCoreEnd >=
291 GetPortionData().GetFirstValidCorePosition() )
293 // selection is inside our part of this para
294 DBG_ASSERT(
295 GetPortionData().IsValidCorePosition(
296 nCoreEnd ),
297 "problem determining valid core position" );
299 nLocalEnd = GetPortionData().GetAccessiblePosition(
300 nCoreEnd );
304 if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
306 nStart = nLocalStart;
307 nEnd = nLocalEnd;
308 bRet = sal_True;
311 // else: this PaM doesn't point to this paragraph
313 // else: this PaM is collapsed and doesn't select anything
315 // next PaM in ring
316 pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
318 while( !bRet && (pCrsr != pRingStart) );
320 // else: nocursor -> no selection
322 return bRet;
325 // --> OD 2005-12-20 #i27301# - new parameter <_bForSelection>
326 SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection )
328 // get the cursor shell; if we don't have any, we don't have a
329 // cursor/selection either
330 SwPaM* pCrsr = NULL;
331 SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
332 // --> OD 2005-12-20 #i27301#
333 // - if cursor is retrieved for selection, the cursors for a table selection
334 // has to be returned.
335 if ( pCrsrShell != NULL &&
336 ( _bForSelection || !pCrsrShell->IsTableMode() ) )
337 // <--
339 SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell )
340 ? static_cast< SwFEShell * >( pCrsrShell ) : 0;
341 if( !pFESh ||
342 !(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) )
344 // get the selection, and test whether it affects our text node
345 pCrsr = pCrsrShell->GetCrsr( FALSE /* ??? */ );
349 return pCrsr;
352 sal_Bool SwAccessibleParagraph::IsHeading() const
354 const SwTxtNode *pTxtNd = GetTxtNode();
355 return pTxtNd->IsOutline();
358 void SwAccessibleParagraph::GetStates(
359 ::utl::AccessibleStateSetHelper& rStateSet )
361 SwAccessibleContext::GetStates( rStateSet );
363 // MULTILINE
364 rStateSet.AddState( AccessibleStateType::MULTI_LINE );
366 // MULTISELECTABLE
367 SwCrsrShell *pCrsrSh = GetCrsrShell();
368 if( pCrsrSh )
369 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
371 // FOCUSABLE
372 if( pCrsrSh )
373 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
375 // FOCUSED (simulates node index of cursor)
376 // --> OD 2005-12-20 #i27301# - consider adjusted method signature
377 SwPaM* pCaret = GetCursor( false );
378 // <--
379 const SwTxtNode* pTxtNd = GetTxtNode();
380 if( pCaret != 0 && pTxtNd != 0 &&
381 pTxtNd->GetIndex() == pCaret->GetPoint()->nNode.GetIndex() &&
382 nOldCaretPos != -1)
384 Window *pWin = GetWindow();
385 if( pWin && pWin->HasFocus() )
386 rStateSet.AddState( AccessibleStateType::FOCUSED );
387 ::vos::ORef < SwAccessibleContext > xThis( this );
388 GetMap()->SetCursorContext( xThis );
392 void SwAccessibleParagraph::_InvalidateContent( sal_Bool bVisibleDataFired )
394 OUString sOldText( GetString() );
396 ClearPortionData();
398 const OUString& rText = GetString();
400 if( rText != sOldText )
402 // The text is changed
403 AccessibleEventObject aEvent;
404 aEvent.EventId = AccessibleEventId::TEXT_CHANGED;
406 // determine exact changes between sOldText and rText
407 comphelper::OCommonAccessibleText::implInitTextChangedEvent(
408 sOldText, rText,
409 aEvent.OldValue, aEvent.NewValue );
411 FireAccessibleEvent( aEvent );
413 else if( !bVisibleDataFired )
415 FireVisibleDataEvent();
418 sal_Bool bNewIsHeading = IsHeading();
419 sal_Bool bOldIsHeading;
421 vos::OGuard aGuard( aMutex );
422 bOldIsHeading = bIsHeading;
423 if( bIsHeading != bNewIsHeading )
424 bIsHeading = bNewIsHeading;
428 if( bNewIsHeading != bOldIsHeading || rText != sOldText )
430 OUString sNewDesc( GetDescription() );
431 OUString sOldDesc;
433 vos::OGuard aGuard( aMutex );
434 sOldDesc = sDesc;
435 if( sDesc != sNewDesc )
436 sDesc = sNewDesc;
439 if( sNewDesc != sOldDesc )
441 // The text is changed
442 AccessibleEventObject aEvent;
443 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
444 aEvent.OldValue <<= sOldDesc;
445 aEvent.NewValue <<= sNewDesc;
447 FireAccessibleEvent( aEvent );
452 void SwAccessibleParagraph::_InvalidateCursorPos()
454 // The text is changed
455 sal_Int32 nNew = GetCaretPos();
456 sal_Int32 nOld;
458 vos::OGuard aGuard( aMutex );
459 nOld = nOldCaretPos;
460 nOldCaretPos = nNew;
462 if( -1 != nNew )
464 // remember that object as the one that has the caret. This is
465 // neccessary to notify that object if the cursor leaves it.
466 ::vos::ORef < SwAccessibleContext > xThis( this );
467 GetMap()->SetCursorContext( xThis );
470 Window *pWin = GetWindow();
471 if( nOld != nNew )
473 // The cursor's node position is sumilated by the focus!
474 if( pWin && pWin->HasFocus() && -1 == nOld )
475 FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True );
478 AccessibleEventObject aEvent;
479 aEvent.EventId = AccessibleEventId::CARET_CHANGED;
480 aEvent.OldValue <<= nOld;
481 aEvent.NewValue <<= nNew;
483 FireAccessibleEvent( aEvent );
485 if( pWin && pWin->HasFocus() && -1 == nNew )
486 FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_False );
490 void SwAccessibleParagraph::_InvalidateFocus()
492 Window *pWin = GetWindow();
493 if( pWin )
495 sal_Int32 nPos;
497 vos::OGuard aGuard( aMutex );
498 nPos = nOldCaretPos;
500 ASSERT( nPos != -1, "focus object should be selected" );
502 FireStateChangedEvent( AccessibleStateType::FOCUSED,
503 pWin->HasFocus() && nPos != -1 );
507 SwAccessibleParagraph::SwAccessibleParagraph(
508 SwAccessibleMap* pInitMap,
509 const SwTxtFrm *pTxtFrm ) :
510 SwAccessibleContext( pInitMap, AccessibleRole::PARAGRAPH, pTxtFrm ),
511 pPortionData( NULL ),
512 pHyperTextData( NULL ),
513 nOldCaretPos( -1 ),
514 aSelectionHelper( *this )
516 vos::OGuard aGuard(Application::GetSolarMutex());
518 bIsHeading = IsHeading();
519 // --> OD 2004-09-27 #117970# - set an empty accessibility name for paragraphs
520 SetName( OUString() );
521 // <--
523 // If this object has the focus, then it is remembered by the map itself.
524 nOldCaretPos = GetCaretPos();
527 SwAccessibleParagraph::~SwAccessibleParagraph()
529 vos::OGuard aGuard(Application::GetSolarMutex());
531 delete pPortionData;
532 delete pHyperTextData;
535 sal_Bool SwAccessibleParagraph::HasCursor()
537 vos::OGuard aGuard( aMutex );
538 return nOldCaretPos != -1;
541 void SwAccessibleParagraph::UpdatePortionData()
542 throw( uno::RuntimeException )
544 // obtain the text frame
545 DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
546 DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
547 const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
549 // build new portion data
550 delete pPortionData;
551 pPortionData = new SwAccessiblePortionData(
552 pFrm->GetTxtNode(), GetMap()->GetShell()->GetViewOptions() );
553 pFrm->VisitPortions( *pPortionData );
555 DBG_ASSERT( pPortionData != NULL, "UpdatePortionData() failed" );
558 void SwAccessibleParagraph::ClearPortionData()
560 delete pPortionData;
561 pPortionData = NULL;
563 delete pHyperTextData;
564 pHyperTextData = 0;
568 void SwAccessibleParagraph::ExecuteAtViewShell( UINT16 nSlot )
570 DBG_ASSERT( GetMap() != NULL, "no map?" );
571 ViewShell* pViewShell = GetMap()->GetShell();
573 DBG_ASSERT( pViewShell != NULL, "View shell exptected!" );
574 SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell();
576 DBG_ASSERT( pSfxShell != NULL, "SfxViewShell shell exptected!" );
577 if( !pSfxShell )
578 return;
580 SfxViewFrame *pFrame = pSfxShell->GetViewFrame();
581 DBG_ASSERT( pFrame != NULL, "View frame exptected!" );
582 if( !pFrame )
583 return;
585 SfxDispatcher *pDispatcher = pFrame->GetDispatcher();
586 DBG_ASSERT( pDispatcher != NULL, "Dispatcher exptected!" );
587 if( !pDispatcher )
588 return;
590 pDispatcher->Execute( nSlot );
593 SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion(
594 sal_Int32 nStartIndex,
595 sal_Int32 nEndIndex )
597 DBG_ASSERT( (IsValidChar(nStartIndex, GetString().getLength()) &&
598 (nEndIndex == -1)) ||
599 IsValidRange(nStartIndex, nEndIndex, GetString().getLength()),
600 "please check parameters before calling this method" );
602 USHORT nStart = GetPortionData().GetModelPosition( nStartIndex );
603 USHORT nEnd = (nEndIndex == -1) ? (nStart + 1) :
604 GetPortionData().GetModelPosition( nEndIndex );
606 // create UNO cursor
607 SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() );
608 SwIndex aIndex( pTxtNode, nStart );
609 SwPosition aStartPos( *pTxtNode, aIndex );
610 SwUnoCrsr* pUnoCursor = pTxtNode->GetDoc()->CreateUnoCrsr( aStartPos );
611 pUnoCursor->SetMark();
612 pUnoCursor->GetMark()->nContent = nEnd;
614 // create a (dummy) text portion to be returned
615 uno::Reference<text::XText> aEmpty;
616 SwXTextPortion* pPortion =
617 new SwXTextPortion ( pUnoCursor, aEmpty, PORTION_TEXT);
618 delete pUnoCursor;
620 return pPortion;
625 // range checking for parameter
628 sal_Bool SwAccessibleParagraph::IsValidChar(
629 sal_Int32 nPos, sal_Int32 nLength)
631 return (nPos >= 0) && (nPos < nLength);
634 sal_Bool SwAccessibleParagraph::IsValidPosition(
635 sal_Int32 nPos, sal_Int32 nLength)
637 return (nPos >= 0) && (nPos <= nLength);
640 sal_Bool SwAccessibleParagraph::IsValidRange(
641 sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength)
643 return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength);
648 // text boundaries
652 sal_Bool SwAccessibleParagraph::GetCharBoundary(
653 Boundary& rBound,
654 const OUString&,
655 sal_Int32 nPos )
657 rBound.startPos = nPos;
658 rBound.endPos = nPos+1;
659 return sal_True;
662 sal_Bool SwAccessibleParagraph::GetWordBoundary(
663 Boundary& rBound,
664 const OUString& rText,
665 sal_Int32 nPos )
667 sal_Bool bRet = sal_False;
669 // now ask the Break-Iterator for the word
670 DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
671 DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
672 if( pBreakIt->GetBreakIter().is() )
674 // get locale for this position
675 USHORT nModelPos = GetPortionData().GetModelPosition( nPos );
676 Locale aLocale = pBreakIt->GetLocale(
677 GetTxtNode()->GetLang( nModelPos ) );
679 // which type of word are we interested in?
680 // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.)
681 const USHORT nWordType = WordType::ANY_WORD;
683 // get word boundary, as the Break-Iterator sees fit.
684 rBound = pBreakIt->GetBreakIter()->getWordBoundary(
685 rText, nPos, aLocale, nWordType, sal_True );
687 // It's a word if the first character is an alpha-numeric character.
688 bRet = GetAppCharClass().isLetterNumeric(
689 rText.getStr()[ rBound.startPos ] );
691 else
693 // no break Iterator -> no word
694 rBound.startPos = nPos;
695 rBound.endPos = nPos;
698 return bRet;
701 sal_Bool SwAccessibleParagraph::GetSentenceBoundary(
702 Boundary& rBound,
703 const OUString&,
704 sal_Int32 nPos )
706 GetPortionData().GetSentenceBoundary( rBound, nPos );
707 return sal_True;
710 sal_Bool SwAccessibleParagraph::GetLineBoundary(
711 Boundary& rBound,
712 const OUString& rText,
713 sal_Int32 nPos )
715 if( rText.getLength() == nPos )
716 GetPortionData().GetLastLineBoundary( rBound );
717 else
718 GetPortionData().GetLineBoundary( rBound, nPos );
719 return sal_True;
722 sal_Bool SwAccessibleParagraph::GetParagraphBoundary(
723 Boundary& rBound,
724 const OUString& rText,
725 sal_Int32 )
727 rBound.startPos = 0;
728 rBound.endPos = rText.getLength();
729 return sal_True;
732 sal_Bool SwAccessibleParagraph::GetAttributeBoundary(
733 Boundary& rBound,
734 const OUString&,
735 sal_Int32 nPos )
737 GetPortionData().GetAttributeBoundary( rBound, nPos );
738 return sal_True;
741 sal_Bool SwAccessibleParagraph::GetGlyphBoundary(
742 Boundary& rBound,
743 const OUString& rText,
744 sal_Int32 nPos )
746 sal_Bool bRet = sal_False;
748 // ask the Break-Iterator for the glyph by moving one cell
749 // forward, and then one cell back
750 DBG_ASSERT( pBreakIt != NULL, "We always need a break." );
751 DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." );
752 if( pBreakIt->GetBreakIter().is() )
754 // get locale for this position
755 USHORT nModelPos = GetPortionData().GetModelPosition( nPos );
756 Locale aLocale = pBreakIt->GetLocale(
757 GetTxtNode()->GetLang( nModelPos ) );
759 // get word boundary, as the Break-Iterator sees fit.
760 const USHORT nIterMode = CharacterIteratorMode::SKIPCELL;
761 sal_Int32 nDone = 0;
762 rBound.endPos = pBreakIt->GetBreakIter()->nextCharacters(
763 rText, nPos, aLocale, nIterMode, 1, nDone );
764 rBound.startPos = pBreakIt->GetBreakIter()->previousCharacters(
765 rText, rBound.endPos, aLocale, nIterMode, 1, nDone );
767 DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" );
768 DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" );
770 else
772 // no break Iterator -> no glyph
773 rBound.startPos = nPos;
774 rBound.endPos = nPos;
777 return bRet;
781 sal_Bool SwAccessibleParagraph::GetTextBoundary(
782 Boundary& rBound,
783 const OUString& rText,
784 sal_Int32 nPos,
785 sal_Int16 nTextType )
786 throw (
787 IndexOutOfBoundsException,
788 IllegalArgumentException,
789 uno::RuntimeException)
791 // error checking
792 if( !( AccessibleTextType::LINE == nTextType
793 ? IsValidPosition( nPos, rText.getLength() )
794 : IsValidChar( nPos, rText.getLength() ) ) )
795 throw IndexOutOfBoundsException();
797 sal_Bool bRet;
799 switch( nTextType )
801 case AccessibleTextType::WORD:
802 bRet = GetWordBoundary( rBound, rText, nPos );
803 break;
805 case AccessibleTextType::SENTENCE:
806 bRet = GetSentenceBoundary( rBound, rText, nPos );
807 break;
809 case AccessibleTextType::PARAGRAPH:
810 bRet = GetParagraphBoundary( rBound, rText, nPos );
811 break;
813 case AccessibleTextType::CHARACTER:
814 bRet = GetCharBoundary( rBound, rText, nPos );
815 break;
817 case AccessibleTextType::LINE:
818 bRet = GetLineBoundary( rBound, rText, nPos );
819 break;
821 case AccessibleTextType::ATTRIBUTE_RUN:
822 bRet = GetAttributeBoundary( rBound, rText, nPos );
823 break;
825 case AccessibleTextType::GLYPH:
826 bRet = GetGlyphBoundary( rBound, rText, nPos );
827 break;
829 default:
830 throw IllegalArgumentException( );
833 return bRet;
836 OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void)
837 throw (uno::RuntimeException)
839 vos::OGuard aGuard(Application::GetSolarMutex());
841 CHECK_FOR_DEFUNC( XAccessibleContext );
843 vos::OGuard aGuard2( aMutex );
844 if( !sDesc.getLength() )
845 sDesc = GetDescription();
847 return sDesc;
850 Locale SAL_CALL SwAccessibleParagraph::getLocale (void)
851 throw (IllegalAccessibleComponentStateException, uno::RuntimeException)
853 vos::OGuard aGuard(Application::GetSolarMutex());
855 SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() );
856 if( !pTxtFrm )
858 THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" );
861 const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode();
862 Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) );
864 return aLoc;
867 /** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
869 OD 2005-12-02 #i27138#
871 @author OD
873 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
874 throw ( uno::RuntimeException )
876 vos::OGuard aGuard(Application::GetSolarMutex());
877 CHECK_FOR_DEFUNC( XAccessibleContext );
879 utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
881 const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm());
882 ASSERT( pTxtFrm,
883 "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame");
884 if ( pTxtFrm )
886 const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) );
887 if ( pPrevCntFrm )
889 uno::Sequence< uno::Reference<XInterface> > aSequence(1);
890 aSequence[0] = GetMap()->GetContext( pPrevCntFrm );
891 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
892 aSequence );
893 pHelper->AddRelation( aAccRel );
896 const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) );
897 if ( pNextCntFrm )
899 uno::Sequence< uno::Reference<XInterface> > aSequence(1);
900 aSequence[0] = GetMap()->GetContext( pNextCntFrm );
901 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
902 aSequence );
903 pHelper->AddRelation( aAccRel );
907 return pHelper;
910 void SAL_CALL SwAccessibleParagraph::grabFocus()
911 throw (uno::RuntimeException)
913 vos::OGuard aGuard(Application::GetSolarMutex());
915 CHECK_FOR_DEFUNC( XAccessibleContext );
917 // get cursor shell
918 SwCrsrShell *pCrsrSh = GetCrsrShell();
919 // --> OD 2005-12-20 #i27301# - consider new method signature
920 SwPaM *pCrsr = GetCursor( false );
921 // <--
922 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
923 const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode();
925 if( pCrsrSh != 0 && pTxtNd != 0 &&
926 ( pCrsr == 0 ||
927 pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() ||
928 !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) )
930 // create pam for selection
931 SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ),
932 pTxtFrm->GetOfst() );
933 SwPosition aStartPos( *pTxtNd, aIndex );
934 SwPaM aPaM( aStartPos );
936 // set PaM at cursor shell
937 Select( aPaM );
942 /* ->#i13955# */
943 Window * pWindow = GetWindow();
945 if (pWindow != NULL)
946 pWindow->GrabFocus();
947 /* <-#i13955# */
950 // --> OD 2007-01-17 #i71385#
951 bool lcl_GetBackgroundColor( Color & rColor,
952 const SwFrm* pFrm,
953 SwCrsrShell* pCrsrSh )
955 const SvxBrushItem* pBackgrdBrush = 0;
956 const Color* pSectionTOXColor = 0;
957 SwRect aDummyRect;
958 if ( pFrm &&
959 pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) )
961 if ( pSectionTOXColor )
963 rColor = *pSectionTOXColor;
964 return true;
966 else
968 rColor = pBackgrdBrush->GetColor();
969 return true;
972 else if ( pCrsrSh )
974 rColor = pCrsrSh->Imp()->GetRetoucheColor();
975 return true;
978 return false;
981 sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground()
982 throw (uno::RuntimeException)
984 Color aBackgroundCol;
986 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
988 if ( aBackgroundCol.IsDark() )
990 return COL_WHITE;
992 else
994 return COL_BLACK;
998 return SwAccessibleContext::getForeground();
1001 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
1002 throw (uno::RuntimeException)
1004 Color aBackgroundCol;
1006 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
1008 return aBackgroundCol.GetColor();
1011 return SwAccessibleContext::getBackground();
1013 // <--
1015 OUString SAL_CALL SwAccessibleParagraph::getImplementationName()
1016 throw( uno::RuntimeException )
1018 return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
1021 sal_Bool SAL_CALL SwAccessibleParagraph::supportsService(
1022 const ::rtl::OUString& sTestServiceName)
1023 throw (uno::RuntimeException)
1025 return sTestServiceName.equalsAsciiL( sServiceName,
1026 sizeof(sServiceName)-1 ) ||
1027 sTestServiceName.equalsAsciiL( sAccessibleServiceName,
1028 sizeof(sAccessibleServiceName)-1 );
1031 Sequence< OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames()
1032 throw( uno::RuntimeException )
1034 Sequence< OUString > aRet(2);
1035 OUString* pArray = aRet.getArray();
1036 pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
1037 pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
1038 return aRet;
1042 //===== XInterface =======================================================
1045 Any SwAccessibleParagraph::queryInterface( const Type& rType )
1046 throw (RuntimeException)
1048 Any aRet;
1049 if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) )
1051 uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity
1052 aRet <<= aAccText;
1054 else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) )
1056 uno::Reference<XAccessibleEditableText> aAccEditText = this;
1057 aRet <<= aAccEditText;
1059 else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) )
1061 uno::Reference<XAccessibleSelection> aAccSel = this;
1062 aRet <<= aAccSel;
1064 else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) )
1066 uno::Reference<XAccessibleHypertext> aAccHyp = this;
1067 aRet <<= aAccHyp;
1069 // --> OD 2006-07-13 #i63870#
1070 // add interface com::sun:star:accessibility::XAccessibleTextAttributes
1071 else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) )
1073 uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
1074 aRet <<= aAccTextAttr;
1076 // <--
1077 // --> OD 2008-06-10 #i89175#
1078 // add interface com::sun:star:accessibility::XAccessibleTextMarkup
1079 else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) )
1081 uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this;
1082 aRet <<= aAccTextMarkup;
1084 // add interface com::sun:star:accessibility::XAccessibleMultiLineText
1085 else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) )
1087 uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this;
1088 aRet <<= aAccMultiLineText;
1090 // <--
1091 else
1093 aRet = SwAccessibleContext::queryInterface(rType);
1096 return aRet;
1099 //====== XTypeProvider ====================================================
1100 Sequence< Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(RuntimeException)
1102 Sequence< Type > aTypes( SwAccessibleContext::getTypes() );
1104 sal_Int32 nIndex = aTypes.getLength();
1105 // --> OD 2006-07-13 #i63870#
1106 // add type accessibility::XAccessibleTextAttributes
1107 // --> OD 2008-06-10 #i89175#
1108 // add type accessibility::XAccessibleTextMarkup and accessibility::XAccessibleMultiLineText
1109 aTypes.realloc( nIndex + 6 );
1111 Type* pTypes = aTypes.getArray();
1112 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) );
1113 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) );
1114 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) );
1115 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) );
1116 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) );
1117 pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) );
1118 // <--
1120 return aTypes;
1123 Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId()
1124 throw(RuntimeException)
1126 vos::OGuard aGuard(Application::GetSolarMutex());
1127 static Sequence< sal_Int8 > aId( 16 );
1128 static sal_Bool bInit = sal_False;
1129 if(!bInit)
1131 rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
1132 bInit = sal_True;
1134 return aId;
1139 //===== XAccesibleText ===================================================
1142 sal_Int32 SwAccessibleParagraph::getCaretPosition()
1143 throw (RuntimeException)
1145 vos::OGuard aGuard(Application::GetSolarMutex());
1147 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1149 sal_Int32 nRet = GetCaretPos();
1151 vos::OGuard aOldCaretPosGuard( aMutex );
1152 ASSERT( nRet == nOldCaretPos, "caret pos out of sync" );
1153 nOldCaretPos = nRet;
1155 if( -1 != nRet )
1157 ::vos::ORef < SwAccessibleContext > xThis( this );
1158 GetMap()->SetCursorContext( xThis );
1161 return nRet;
1164 sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
1165 throw (IndexOutOfBoundsException, uno::RuntimeException)
1167 vos::OGuard aGuard(Application::GetSolarMutex());
1169 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1171 // parameter checking
1172 sal_Int32 nLength = GetString().getLength();
1173 if ( ! IsValidPosition( nIndex, nLength ) )
1175 throw IndexOutOfBoundsException();
1178 sal_Bool bRet = sal_False;
1180 // get cursor shell
1181 SwCrsrShell* pCrsrShell = GetCrsrShell();
1182 if( pCrsrShell != NULL )
1184 // create pam for selection
1185 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1186 SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex));
1187 SwPosition aStartPos( *pNode, aIndex );
1188 SwPaM aPaM( aStartPos );
1190 // set PaM at cursor shell
1191 bRet = Select( aPaM );
1194 return bRet;
1197 sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex )
1198 throw (IndexOutOfBoundsException, uno::RuntimeException)
1200 vos::OGuard aGuard(Application::GetSolarMutex());
1202 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1204 OUString sText( GetString() );
1206 // return character (if valid)
1207 if( IsValidChar(nIndex, sText.getLength() ) )
1209 return sText.getStr()[nIndex];
1211 else
1212 throw IndexOutOfBoundsException();
1215 // --> OD 2006-07-20 #i63870#
1216 // re-implement method on behalf of methods <_getDefaultAttributesImpl(..)> and
1217 // <_getRunAttributesImpl(..)>
1218 Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes(
1219 sal_Int32 nIndex,
1220 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes )
1221 throw (IndexOutOfBoundsException, uno::RuntimeException)
1224 vos::OGuard aGuard(Application::GetSolarMutex());
1225 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1227 const OUString& rText = GetString();
1229 if( ! IsValidChar( nIndex, rText.getLength() ) )
1230 throw IndexOutOfBoundsException();
1232 // retrieve default character attributes
1233 tAccParaPropValMap aDefAttrSeq;
1234 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true );
1236 // retrieved run character attributes
1237 tAccParaPropValMap aRunAttrSeq;
1238 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1240 // merge default and run attributes
1241 Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1242 PropertyValue* pValues = aValues.getArray();
1243 sal_Int32 i = 0;
1244 for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin();
1245 aDefIter != aDefAttrSeq.end();
1246 ++aDefIter )
1248 tAccParaPropValMap::const_iterator aRunIter =
1249 aRunAttrSeq.find( aDefIter->first );
1250 if ( aRunIter != aRunAttrSeq.end() )
1252 pValues[i] = aRunIter->second;
1254 else
1256 pValues[i] = aDefIter->second;
1258 ++i;
1261 // // create a (dummy) text portion for the sole purpose of calling
1262 // // getPropertyValues on it
1263 // Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 );
1265 // // get values
1266 // Sequence<OUString> aNames = getAttributeNames();
1267 // sal_Int32 nLength = aNames.getLength();
1268 // Sequence<Any> aAnys( nLength );
1269 // aAnys = xPortion->getPropertyValues( aNames );
1271 // // copy names + anys into return sequence
1272 // Sequence<PropertyValue> aValues( aNames.getLength() );
1273 // const OUString* pNames = aNames.getConstArray();
1274 // const Any* pAnys = aAnys.getConstArray();
1275 // PropertyValue* pValues = aValues.getArray();
1276 // for( sal_Int32 i = 0; i < nLength; i++ )
1277 // {
1278 // PropertyValue& rValue = pValues[i];
1279 // rValue.Name = pNames[i];
1280 // rValue.Value = pAnys[i];
1281 // rValue.Handle = -1; // handle not supported
1282 // rValue.State = PropertyState_DIRECT_VALUE; // states not supported
1283 // }
1285 // // adjust background color if we're in a gray portion
1286 // DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name.
1287 // equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")),
1288 // "Please adjust CHAR_BACK_COLOR_POS constant." );
1289 // if( GetPortionData().IsInGrayPortion( nIndex ) )
1290 // pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor();
1292 return aValues;
1295 // --> OD 2006-07-11 #i63870#
1296 void SwAccessibleParagraph::_getDefaultAttributesImpl(
1297 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1298 tAccParaPropValMap& rDefAttrSeq,
1299 const bool bOnlyCharAttrs )
1301 // retrieve default attributes
1302 const SwTxtNode* pTxtNode( GetTxtNode() );
1303 ::boost::scoped_ptr<SfxItemSet> pSet;
1304 if ( !bOnlyCharAttrs )
1306 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1307 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1308 RES_PARATR_BEGIN, RES_PARATR_END - 1,
1309 RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1310 0 ) );
1312 else
1314 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1315 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1316 0 ) );
1318 // --> OD 2007-11-12 #i82637#
1319 // From the perspective of the a11y API the default character attributes
1320 // are the character attributes, which are set at the paragraph style
1321 // of the paragraph. The character attributes set at the automatic paragraph
1322 // style of the paragraph are treated as run attributes.
1323 // pTxtNode->SwCntntNode::GetAttr( *pSet );
1324 // get default paragraph attributes, if needed, and merge these into <pSet>
1325 if ( !bOnlyCharAttrs )
1327 SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1328 RES_PARATR_BEGIN, RES_PARATR_END - 1,
1329 RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1330 0 );
1331 pTxtNode->SwCntntNode::GetAttr( aParaSet );
1332 pSet->Put( aParaSet );
1334 // get default character attributes and merge these into <pSet>
1335 ASSERT( pTxtNode->GetTxtColl(),
1336 "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" );
1337 if ( pTxtNode->GetTxtColl() )
1339 SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1340 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1341 0 );
1342 aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() );
1343 pSet->Put( aCharSet );
1345 // <--
1347 // build-up sequence containing the run attributes <rDefAttrSeq>
1348 tAccParaPropValMap aDefAttrSeq;
1350 const SfxItemPropertyMap* pPropMap =
1351 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1352 PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
1353 PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1354 while ( aPropIt != aPropertyEntries.end() )
1356 const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID );
1357 if ( pItem )
1359 Any aVal;
1360 pItem->QueryValue( aVal, aPropIt->nMemberId );
1362 PropertyValue rPropVal;
1363 rPropVal.Name = aPropIt->sName;
1364 rPropVal.Value = aVal;
1365 rPropVal.Handle = -1;
1366 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1368 aDefAttrSeq[rPropVal.Name] = rPropVal;
1370 ++aPropIt;
1373 // --> OD 2007-01-15 #i72800#
1374 // add property value entry for the paragraph style
1375 if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() )
1377 const OUString sParaStyleName =
1378 OUString::createFromAscii(
1379 GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName );
1380 if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() )
1382 PropertyValue rPropVal;
1383 rPropVal.Name = sParaStyleName;
1384 Any aVal( makeAny( OUString( pTxtNode->GetTxtColl()->GetName() ) ) );
1385 rPropVal.Value = aVal;
1386 rPropVal.Handle = -1;
1387 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1389 aDefAttrSeq[rPropVal.Name] = rPropVal;
1392 // <--
1394 // --> OD 2007-01-15 #i73371#
1395 // resolve value text::WritingMode2::PAGE of property value entry WritingMode
1396 if ( !bOnlyCharAttrs && GetFrm() )
1398 const OUString sWritingMode =
1399 OUString::createFromAscii(
1400 GetPropName( UNO_NAME_WRITING_MODE ).pName );
1401 tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode );
1402 if ( aIter != aDefAttrSeq.end() )
1404 PropertyValue rPropVal( aIter->second );
1405 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
1406 if ( nVal == text::WritingMode2::PAGE )
1408 const SwFrm* pUpperFrm( GetFrm()->GetUpper() );
1409 while ( pUpperFrm )
1411 if ( pUpperFrm->GetType() &
1412 ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) )
1414 if ( pUpperFrm->IsVertical() )
1416 nVal = text::WritingMode2::TB_RL;
1418 else if ( pUpperFrm->IsRightToLeft() )
1420 nVal = text::WritingMode2::RL_TB;
1422 else
1424 nVal = text::WritingMode2::LR_TB;
1426 rPropVal.Value <<= nVal;
1427 aDefAttrSeq[rPropVal.Name] = rPropVal;
1428 break;
1431 if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) )
1433 pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm();
1435 else
1437 pUpperFrm = pUpperFrm->GetUpper();
1443 // <--
1446 if ( aRequestedAttributes.getLength() == 0 )
1448 rDefAttrSeq = aDefAttrSeq;
1450 else
1452 const OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1453 const sal_Int32 nLength = aRequestedAttributes.getLength();
1454 for( sal_Int32 i = 0; i < nLength; ++i )
1456 tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] );
1457 if ( aIter != aDefAttrSeq.end() )
1459 rDefAttrSeq[ aIter->first ] = aIter->second;
1465 Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
1466 const Sequence< ::rtl::OUString >& aRequestedAttributes )
1467 throw ( uno::RuntimeException )
1469 vos::OGuard aGuard(Application::GetSolarMutex());
1470 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1472 tAccParaPropValMap aDefAttrSeq;
1473 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
1475 Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1476 PropertyValue* pValues = aValues.getArray();
1477 sal_Int32 i = 0;
1478 for ( tAccParaPropValMap::const_iterator aIter = aDefAttrSeq.begin();
1479 aIter != aDefAttrSeq.end();
1480 ++aIter )
1482 pValues[i] = aIter->second;
1483 ++i;
1486 return aValues;
1489 void SwAccessibleParagraph::_getRunAttributesImpl(
1490 const sal_Int32 nIndex,
1491 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes,
1492 tAccParaPropValMap& rRunAttrSeq )
1494 // create PaM for character at position <nIndex>
1495 SwPaM* pPaM( 0 );
1497 const SwTxtNode* pTxtNode( GetTxtNode() );
1498 SwPosition* pStartPos = new SwPosition( *pTxtNode );
1499 pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<USHORT>(nIndex) );
1500 SwPosition* pEndPos = new SwPosition( *pTxtNode );
1501 pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<USHORT>(nIndex+1) );
1503 pPaM = new SwPaM( *pStartPos, *pEndPos );
1505 delete pStartPos;
1506 delete pEndPos;
1509 // retrieve character attributes for the created PaM <pPaM>
1510 SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(),
1511 RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1512 0 );
1513 // --> OD 2007-11-12 #i82637#
1514 // From the perspective of the a11y API the character attributes, which
1515 // are set at the automatic paragraph style of the paragraph are treated
1516 // as run attributes.
1517 // SwXTextCursor::GetCrsrAttr( *pPaM, aSet, TRUE, TRUE );
1518 // get character attributes from automatic paragraph style and merge these into <aSet>
1520 const SwTxtNode* pTxtNode( GetTxtNode() );
1521 if ( pTxtNode->HasSwAttrSet() )
1523 SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(),
1524 RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1525 0 );
1526 aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), FALSE );
1527 aSet.Put( aAutomaticParaStyleCharAttrs );
1530 // get character attributes at <pPaM> and merge these into <aSet>
1532 SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(),
1533 RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1534 0 );
1535 SwXTextCursor::GetCrsrAttr( *pPaM, aCharAttrsAtPaM, TRUE, TRUE );
1536 aSet.Put( aCharAttrsAtPaM );
1538 // <--
1540 // build-up sequence containing the run attributes <rRunAttrSeq>
1542 tAccParaPropValMap aRunAttrSeq;
1544 // --> OD 2007-11-12 #i82637#
1545 tAccParaPropValMap aDefAttrSeq;
1546 uno::Sequence< ::rtl::OUString > aDummy;
1547 _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true );
1548 // <--
1550 const SfxItemPropertyMap* pPropMap =
1551 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1552 PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries();
1553 PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1554 while ( aPropIt != aPropertyEntries.end() )
1556 const SfxPoolItem* pItem( 0 );
1557 // --> OD 2007-11-12 #i82637#
1558 // Found character attributes, whose value equals the value of
1559 // the corresponding default character attributes, are excluded.
1560 if ( aSet.GetItemState( aPropIt->nWID, TRUE, &pItem ) == SFX_ITEM_SET )
1562 Any aVal;
1563 pItem->QueryValue( aVal, aPropIt->nMemberId );
1565 PropertyValue rPropVal;
1566 rPropVal.Name = aPropIt->sName;
1567 rPropVal.Value = aVal;
1568 rPropVal.Handle = -1;
1569 rPropVal.State = PropertyState_DIRECT_VALUE;
1571 tAccParaPropValMap::const_iterator aDefIter =
1572 aDefAttrSeq.find( rPropVal.Name );
1573 if ( aDefIter == aDefAttrSeq.end() ||
1574 rPropVal.Value != aDefIter->second.Value )
1576 aRunAttrSeq[rPropVal.Name] = rPropVal;
1580 ++aPropIt;
1584 if ( aRequestedAttributes.getLength() == 0 )
1586 rRunAttrSeq = aRunAttrSeq;
1588 else
1590 const OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1591 const sal_Int32 nLength = aRequestedAttributes.getLength();
1592 for( sal_Int32 i = 0; i < nLength; ++i )
1594 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1595 if ( aIter != aRunAttrSeq.end() )
1597 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1603 delete pPaM;
1606 Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
1607 sal_Int32 nIndex,
1608 const Sequence< ::rtl::OUString >& aRequestedAttributes )
1609 throw ( IndexOutOfBoundsException,
1610 uno::RuntimeException )
1612 vos::OGuard aGuard(Application::GetSolarMutex());
1613 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1616 const OUString& rText = GetString();
1617 if ( !IsValidChar( nIndex, rText.getLength() ) )
1619 throw IndexOutOfBoundsException();
1623 tAccParaPropValMap aRunAttrSeq;
1624 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1626 Sequence< PropertyValue > aValues( aRunAttrSeq.size() );
1627 PropertyValue* pValues = aValues.getArray();
1628 sal_Int32 i = 0;
1629 for ( tAccParaPropValMap::const_iterator aIter = aRunAttrSeq.begin();
1630 aIter != aRunAttrSeq.end();
1631 ++aIter )
1633 pValues[i] = aIter->second;
1634 ++i;
1637 return aValues;
1639 // <--
1641 awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
1642 sal_Int32 nIndex )
1643 throw (IndexOutOfBoundsException, uno::RuntimeException)
1645 vos::OGuard aGuard(Application::GetSolarMutex());
1647 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1650 /* #i12332# The position after the string needs special treatment.
1651 IsValidChar -> IsValidPosition
1653 if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
1654 throw IndexOutOfBoundsException();
1656 /* #i12332# */
1657 sal_Bool bBehindText = sal_False;
1658 if ( nIndex == GetString().getLength() )
1659 bBehindText = sal_True;
1661 // get model position & prepare GetCharRect() arguments
1662 SwCrsrMoveState aMoveState;
1663 aMoveState.bRealHeight = TRUE;
1664 aMoveState.bRealWidth = TRUE;
1665 SwSpecialPos aSpecialPos;
1666 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1668 USHORT nPos = 0;
1670 /* #i12332# FillSpecialPos does not accept nIndex ==
1671 GetString().getLength(). In that case nPos is set to the
1672 length of the string in the core. This way GetCharRect
1673 returns the rectangle for a cursor at the end of the
1674 paragraph. */
1675 if (bBehindText)
1677 nPos = pNode->GetTxt().Len();
1679 else
1680 nPos = GetPortionData().FillSpecialPos
1681 (nIndex, aSpecialPos, aMoveState.pSpecialPos );
1683 // call GetCharRect
1684 SwRect aCoreRect;
1685 SwIndex aIndex( pNode, nPos );
1686 SwPosition aPosition( *pNode, aIndex );
1687 GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
1689 // translate core coordinates into accessibility coordinates
1690 Window *pWin = GetWindow();
1691 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1693 Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
1694 SwRect aFrmLogBounds( GetBounds() ); // twip rel to doc root
1696 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
1697 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
1699 // convert into AWT Rectangle
1700 return awt::Rectangle(
1701 aScreenRect.Left(), aScreenRect.Top(),
1702 aScreenRect.GetWidth(), aScreenRect.GetHeight() );
1705 sal_Int32 SwAccessibleParagraph::getCharacterCount()
1706 throw (RuntimeException)
1708 vos::OGuard aGuard(Application::GetSolarMutex());
1710 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1712 return GetString().getLength();
1715 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
1716 throw (RuntimeException)
1718 vos::OGuard aGuard(Application::GetSolarMutex());
1721 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1723 // construct SwPosition (where GetCrsrOfst() will put the result into)
1724 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1725 SwIndex aIndex( pNode, 0);
1726 SwPosition aPos( *pNode, aIndex );
1728 // construct Point (translate into layout coordinates)
1729 Window *pWin = GetWindow();
1730 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1731 Point aPoint( rPoint.X, rPoint.Y );
1732 SwRect aLogBounds( GetBounds( GetFrm() ) ); // twip rel to doc root
1733 Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
1734 aPoint.X() += aPixPos.X();
1735 aPoint.Y() += aPixPos.Y();
1736 MapMode aMapMode = pWin->GetMapMode();
1737 Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
1738 if( !aLogBounds.IsInside( aCorePoint ) )
1740 /* #i12332# rPoint is may also be in rectangle returned by
1741 getCharacterBounds(getCharacterCount() */
1743 awt::Rectangle aRectEndPos =
1744 getCharacterBounds(getCharacterCount());
1746 if (rPoint.X - aRectEndPos.X >= 0 &&
1747 rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
1748 rPoint.Y - aRectEndPos.Y >= 0 &&
1749 rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
1750 return getCharacterCount();
1752 return -1;
1755 // ask core for position
1756 DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" );
1757 DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
1758 const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
1759 SwCrsrMoveState aMoveState;
1760 aMoveState.bPosMatchesBounds = TRUE;
1761 sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState );
1763 SwIndex aCntntIdx = aPos.nContent;
1764 const xub_StrLen nIndex = aCntntIdx.GetIndex();
1765 if ( nIndex > 0 )
1767 SwRect aResultRect;
1768 pFrm->GetCharRect( aResultRect, aPos );
1769 bool bVert = pFrm->IsVertical();
1770 bool bR2L = pFrm->IsRightToLeft();
1772 if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) ||
1773 ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) ||
1774 ( bR2L && aResultRect.Right() < aCorePoint.X()) )
1776 SwIndex aIdxPrev( pNode, nIndex - 1);
1777 SwPosition aPosPrev( *pNode, aIdxPrev );
1778 SwRect aResultRectPrev;
1779 pFrm->GetCharRect( aResultRectPrev, aPosPrev );
1780 if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ||
1781 ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) ||
1782 ( bR2L && aResultRectPrev.Right() > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) )
1783 aPos = aPosPrev;
1787 return bSuccess ?
1788 GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() )
1789 : -1L;
1792 OUString SwAccessibleParagraph::getSelectedText()
1793 throw (RuntimeException)
1795 vos::OGuard aGuard(Application::GetSolarMutex());
1797 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1799 sal_Int32 nStart, nEnd;
1800 sal_Bool bSelected = GetSelection( nStart, nEnd );
1801 return bSelected ? GetString().copy( nStart, nEnd - nStart ) : OUString();
1804 sal_Int32 SwAccessibleParagraph::getSelectionStart()
1805 throw (RuntimeException)
1807 vos::OGuard aGuard(Application::GetSolarMutex());
1809 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1811 sal_Int32 nStart, nEnd;
1812 GetSelection( nStart, nEnd );
1813 return nStart;
1816 sal_Int32 SwAccessibleParagraph::getSelectionEnd()
1817 throw (RuntimeException)
1819 vos::OGuard aGuard(Application::GetSolarMutex());
1821 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1823 sal_Int32 nStart, nEnd;
1824 GetSelection( nStart, nEnd );
1825 return nEnd;
1828 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1829 throw (IndexOutOfBoundsException, uno::RuntimeException)
1831 vos::OGuard aGuard(Application::GetSolarMutex());
1833 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1835 // parameter checking
1836 sal_Int32 nLength = GetString().getLength();
1837 if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
1839 throw IndexOutOfBoundsException();
1842 sal_Bool bRet = sal_False;
1844 // get cursor shell
1845 SwCrsrShell* pCrsrShell = GetCrsrShell();
1846 if( pCrsrShell != NULL )
1848 // create pam for selection
1849 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1850 SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex));
1851 SwPosition aStartPos( *pNode, aIndex );
1852 SwPaM aPaM( aStartPos );
1853 aPaM.SetMark();
1854 aPaM.GetPoint()->nContent =
1855 GetPortionData().GetModelPosition(nEndIndex);
1857 // set PaM at cursor shell
1858 bRet = Select( aPaM );
1861 return bRet;
1864 OUString SwAccessibleParagraph::getText()
1865 throw (RuntimeException)
1867 vos::OGuard aGuard(Application::GetSolarMutex());
1869 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1871 return GetString();
1874 OUString SwAccessibleParagraph::getTextRange(
1875 sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1876 throw (IndexOutOfBoundsException, uno::RuntimeException)
1878 vos::OGuard aGuard(Application::GetSolarMutex());
1880 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1882 OUString sText( GetString() );
1884 if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
1886 OrderRange( nStartIndex, nEndIndex );
1887 return sText.copy(nStartIndex, nEndIndex-nStartIndex );
1889 else
1890 throw IndexOutOfBoundsException();
1893 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1895 vos::OGuard aGuard(Application::GetSolarMutex());
1897 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1899 /*accessibility::*/TextSegment aResult;
1900 aResult.SegmentStart = -1;
1901 aResult.SegmentEnd = -1;
1903 const OUString rText = GetString();
1904 // implement the silly specification that first position after
1905 // text must return an empty string, rather than throwing an
1906 // IndexOutOfBoundsException, except for LINE, where the last
1907 // line is returned
1908 if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
1909 return aResult;
1911 // with error checking
1912 Boundary aBound;
1913 sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1915 DBG_ASSERT( aBound.startPos >= 0, "illegal boundary" );
1916 DBG_ASSERT( aBound.startPos <= aBound.endPos, "illegal boundary" );
1918 // return word (if present)
1919 if ( bWord )
1921 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1922 aResult.SegmentStart = aBound.startPos;
1923 aResult.SegmentEnd = aBound.endPos;
1926 return aResult;
1929 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1931 vos::OGuard aGuard(Application::GetSolarMutex());
1933 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1935 const OUString rText = GetString();
1937 /*accessibility::*/TextSegment aResult;
1938 aResult.SegmentStart = -1;
1939 aResult.SegmentEnd = -1;
1941 // get starting pos
1942 Boundary aBound;
1943 if (nIndex == rText.getLength())
1944 aBound.startPos = aBound.endPos = nIndex;
1945 else
1947 sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
1949 if ( ! bTmp )
1950 aBound.startPos = aBound.endPos = nIndex;
1953 // now skip to previous word
1954 sal_Bool bWord = sal_False;
1955 while( !bWord )
1957 nIndex = min( nIndex, aBound.startPos ) - 1;
1958 if( nIndex >= 0 )
1959 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1960 else
1961 break; // exit if beginning of string is reached
1964 if ( bWord )
1966 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1967 aResult.SegmentStart = aBound.startPos;
1968 aResult.SegmentEnd = aBound.endPos;
1970 return aResult;
1973 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1975 vos::OGuard aGuard(Application::GetSolarMutex());
1977 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1979 /*accessibility::*/TextSegment aResult;
1980 aResult.SegmentStart = -1;
1981 aResult.SegmentEnd = -1;
1982 const OUString rText = GetString();
1984 // implement the silly specification that first position after
1985 // text must return an empty string, rather than throwing an
1986 // IndexOutOfBoundsException
1987 if( nIndex == rText.getLength() )
1988 return aResult;
1991 // get first word, then skip to next word
1992 Boundary aBound;
1993 GetTextBoundary( aBound, rText, nIndex, nTextType );
1994 sal_Bool bWord = sal_False;
1995 while( !bWord )
1997 nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
1998 if( nIndex < rText.getLength() )
1999 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2000 else
2001 break; // exit if end of string is reached
2004 if ( bWord )
2006 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2007 aResult.SegmentStart = aBound.startPos;
2008 aResult.SegmentEnd = aBound.endPos;
2010 return aResult;
2013 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2014 throw (IndexOutOfBoundsException, uno::RuntimeException)
2016 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
2017 vos::OGuard aGuard(Application::GetSolarMutex());
2019 // select and copy (through dispatch mechanism)
2020 setSelection( nStartIndex, nEndIndex );
2021 ExecuteAtViewShell( SID_COPY );
2022 return sal_True;
2027 //===== XAccesibleEditableText ==========================================
2030 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2031 throw (IndexOutOfBoundsException, uno::RuntimeException)
2033 CHECK_FOR_DEFUNC( XAccessibleEditableText );
2034 vos::OGuard aGuard(Application::GetSolarMutex());
2036 if( !IsEditableState() )
2037 return sal_False;
2039 // select and cut (through dispatch mechanism)
2040 setSelection( nStartIndex, nEndIndex );
2041 ExecuteAtViewShell( SID_CUT );
2042 return sal_True;
2045 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
2046 throw (IndexOutOfBoundsException, uno::RuntimeException)
2048 CHECK_FOR_DEFUNC( XAccessibleEditableText );
2049 vos::OGuard aGuard(Application::GetSolarMutex());
2051 if( !IsEditableState() )
2052 return sal_False;
2054 // select and paste (through dispatch mechanism)
2055 setSelection( nIndex, nIndex );
2056 ExecuteAtViewShell( SID_PASTE );
2057 return sal_True;
2060 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2061 throw (IndexOutOfBoundsException, uno::RuntimeException)
2063 return replaceText( nStartIndex, nEndIndex, OUString() );
2066 sal_Bool SwAccessibleParagraph::insertText( const OUString& sText, sal_Int32 nIndex )
2067 throw (IndexOutOfBoundsException, uno::RuntimeException)
2069 return replaceText( nIndex, nIndex, sText );
2072 sal_Bool SwAccessibleParagraph::replaceText(
2073 sal_Int32 nStartIndex, sal_Int32 nEndIndex,
2074 const OUString& sReplacement )
2075 throw (IndexOutOfBoundsException, uno::RuntimeException)
2077 vos::OGuard aGuard(Application::GetSolarMutex());
2079 CHECK_FOR_DEFUNC( XAccessibleEditableText );
2081 const OUString& rText = GetString();
2083 if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2085 if( !IsEditableState() )
2086 return sal_False;
2088 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2090 // translate positions
2091 USHORT nStart, nEnd;
2092 sal_Bool bSuccess = GetPortionData().GetEditableRange(
2093 nStartIndex, nEndIndex, nStart, nEnd );
2095 // edit only if the range is editable
2096 if( bSuccess )
2098 // create SwPosition for nStartIndex
2099 SwIndex aIndex( pNode, nStart );
2100 SwPosition aStartPos( *pNode, aIndex );
2102 // create SwPosition for nEndIndex
2103 SwPosition aEndPos( aStartPos );
2104 aEndPos.nContent = nEnd;
2106 // now create XTextRange as helper and set string
2107 SwXTextRange::CreateTextRangeFromPosition(
2108 pNode->GetDoc(), aStartPos, &aEndPos)->setString(sReplacement);
2110 // delete portion data
2111 ClearPortionData();
2114 return bSuccess;
2116 else
2117 throw IndexOutOfBoundsException();
2120 struct IndexCompare
2122 const PropertyValue* pValues;
2123 IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
2124 bool operator() ( const sal_Int32& a, const sal_Int32& b ) const
2126 return (pValues[a].Name < pValues[b].Name) ? true : false;
2131 sal_Bool SwAccessibleParagraph::setAttributes(
2132 sal_Int32 nStartIndex,
2133 sal_Int32 nEndIndex,
2134 const Sequence<PropertyValue>& rAttributeSet )
2135 throw (IndexOutOfBoundsException, uno::RuntimeException)
2137 vos::OGuard aGuard(Application::GetSolarMutex());
2138 CHECK_FOR_DEFUNC( XAccessibleEditableText );
2140 const OUString& rText = GetString();
2142 if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2143 throw IndexOutOfBoundsException();
2145 if( !IsEditableState() )
2146 return sal_False;
2149 // create a (dummy) text portion for the sole purpose of calling
2150 // setPropertyValue on it
2151 uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
2152 nEndIndex );
2154 // build sorted index array
2155 sal_Int32 nLength = rAttributeSet.getLength();
2156 const PropertyValue* pPairs = rAttributeSet.getConstArray();
2157 sal_Int32* pIndices = new sal_Int32[nLength];
2158 sal_Int32 i;
2159 for( i = 0; i < nLength; i++ )
2160 pIndices[i] = i;
2161 sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
2163 // create sorted sequences accoring to index array
2164 Sequence<OUString> aNames( nLength );
2165 OUString* pNames = aNames.getArray();
2166 Sequence<Any> aValues( nLength );
2167 Any* pValues = aValues.getArray();
2168 for( i = 0; i < nLength; i++ )
2170 const PropertyValue& rVal = pPairs[pIndices[i]];
2171 pNames[i] = rVal.Name;
2172 pValues[i] = rVal.Value;
2174 delete[] pIndices;
2176 // now set the values
2177 sal_Bool bRet = sal_True;
2180 xPortion->setPropertyValues( aNames, aValues );
2182 catch( UnknownPropertyException e )
2184 // error handling through return code!
2185 bRet = sal_False;
2188 return bRet;
2191 sal_Bool SwAccessibleParagraph::setText( const OUString& sText )
2192 throw (RuntimeException)
2194 return replaceText(0, GetString().getLength(), sText);
2197 //===== XAccessibleSelection ============================================
2199 void SwAccessibleParagraph::selectAccessibleChild(
2200 sal_Int32 nChildIndex )
2201 throw ( IndexOutOfBoundsException,
2202 uno::RuntimeException )
2204 CHECK_FOR_DEFUNC( XAccessibleSelection );
2206 aSelectionHelper.selectAccessibleChild(nChildIndex);
2209 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
2210 sal_Int32 nChildIndex )
2211 throw ( IndexOutOfBoundsException,
2212 uno::RuntimeException )
2214 CHECK_FOR_DEFUNC( XAccessibleSelection );
2216 return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
2219 void SwAccessibleParagraph::clearAccessibleSelection( )
2220 throw ( uno::RuntimeException )
2222 CHECK_FOR_DEFUNC( XAccessibleSelection );
2224 aSelectionHelper.clearAccessibleSelection();
2227 void SwAccessibleParagraph::selectAllAccessibleChildren( )
2228 throw ( uno::RuntimeException )
2230 CHECK_FOR_DEFUNC( XAccessibleSelection );
2232 aSelectionHelper.selectAllAccessibleChildren();
2235 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount( )
2236 throw ( uno::RuntimeException )
2238 CHECK_FOR_DEFUNC( XAccessibleSelection );
2240 return aSelectionHelper.getSelectedAccessibleChildCount();
2243 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
2244 sal_Int32 nSelectedChildIndex )
2245 throw ( IndexOutOfBoundsException,
2246 uno::RuntimeException)
2248 CHECK_FOR_DEFUNC( XAccessibleSelection );
2250 return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
2253 // --> OD 2004-11-16 #111714# - index has to be treated as global child index.
2254 void SwAccessibleParagraph::deselectAccessibleChild(
2255 sal_Int32 nChildIndex )
2256 throw ( IndexOutOfBoundsException,
2257 uno::RuntimeException )
2259 CHECK_FOR_DEFUNC( XAccessibleSelection );
2261 aSelectionHelper.deselectAccessibleChild( nChildIndex );
2264 //===== XAccessibleHypertext ============================================
2266 class SwHyperlinkIter_Impl
2268 const SwpHints *pHints;
2269 xub_StrLen nStt;
2270 xub_StrLen nEnd;
2271 sal_uInt16 nPos;
2273 public:
2274 SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm );
2275 const SwTxtAttr *next();
2276 sal_uInt16 getCurrHintPos() const { return nPos-1; }
2278 xub_StrLen startIdx() const { return nStt; }
2279 xub_StrLen endIdx() const { return nEnd; }
2282 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) :
2283 pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ),
2284 nStt( pTxtFrm->GetOfst() ),
2285 nPos( 0 )
2287 const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow();
2288 nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len();
2291 const SwTxtAttr *SwHyperlinkIter_Impl::next()
2293 const SwTxtAttr *pAttr = 0;
2294 if( pHints )
2296 while( !pAttr && nPos < pHints->Count() )
2298 const SwTxtAttr *pHt = (*pHints)[nPos];
2299 if( RES_TXTATR_INETFMT == pHt->Which() )
2301 xub_StrLen nHtStt = *pHt->GetStart();
2302 xub_StrLen nHtEnd = *pHt->GetAnyEnd();
2303 if( nHtEnd > nHtStt &&
2304 ( (nHtStt >= nStt && nHtStt < nEnd) ||
2305 (nHtEnd > nStt && nHtEnd <= nEnd) ) )
2307 pAttr = pHt;
2310 ++nPos;
2314 return pAttr;
2317 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
2318 throw (RuntimeException)
2320 vos::OGuard aGuard(Application::GetSolarMutex());
2322 CHECK_FOR_DEFUNC( XAccessibleHypertext );
2324 sal_Int32 nCount = 0;
2325 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2326 // if( !IsEditableState() )
2327 // <--
2329 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2330 SwHyperlinkIter_Impl aIter( pTxtFrm );
2331 while( aIter.next() )
2332 nCount++;
2335 return nCount;
2338 uno::Reference< XAccessibleHyperlink > SAL_CALL
2339 SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
2340 throw (IndexOutOfBoundsException, uno::RuntimeException)
2342 vos::OGuard aGuard(Application::GetSolarMutex());
2343 CHECK_FOR_DEFUNC( XAccessibleHypertext );
2345 uno::Reference< XAccessibleHyperlink > xRet;
2347 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2348 // if( !IsEditableState() )
2349 // <--
2351 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2352 SwHyperlinkIter_Impl aHIter( pTxtFrm );
2353 while( nLinkIndex-- )
2354 aHIter.next();
2356 const SwTxtAttr *pHt = aHIter.next();
2357 if( pHt )
2359 if( !pHyperTextData )
2360 pHyperTextData = new SwAccessibleHyperTextData;
2361 SwAccessibleHyperTextData::iterator aIter =
2362 pHyperTextData ->find( pHt );
2363 if( aIter != pHyperTextData->end() )
2365 xRet = (*aIter).second;
2367 if( !xRet.is() )
2369 sal_Int32 nHStt= GetPortionData().GetAccessiblePosition(
2370 max( aHIter.startIdx(), *pHt->GetStart() ) );
2371 sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition(
2372 min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
2373 xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
2374 this, nHStt, nHEnd );
2375 if( aIter != pHyperTextData->end() )
2377 (*aIter).second = xRet;
2379 else
2381 SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
2382 pHyperTextData->insert( aEntry );
2388 if( !xRet.is() )
2389 throw IndexOutOfBoundsException();
2391 return xRet;
2394 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
2395 throw (IndexOutOfBoundsException, uno::RuntimeException)
2397 vos::OGuard aGuard(Application::GetSolarMutex());
2398 CHECK_FOR_DEFUNC( XAccessibleHypertext );
2400 // parameter checking
2401 sal_Int32 nLength = GetString().getLength();
2402 if ( ! IsValidPosition( nCharIndex, nLength ) )
2404 throw IndexOutOfBoundsException();
2407 sal_Int32 nRet = -1;
2408 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents.
2409 // if( !IsEditableState() )
2410 // <--
2412 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2413 SwHyperlinkIter_Impl aHIter( pTxtFrm );
2415 xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex );
2416 sal_Int32 nPos = 0;
2417 const SwTxtAttr *pHt = aHIter.next();
2418 while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) )
2420 pHt = aHIter.next();
2421 nPos++;
2424 if( pHt )
2425 nRet = nPos;
2429 return nRet;
2432 // --> OD 2008-05-26 #i71360#
2433 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
2434 throw (lang::IllegalArgumentException,
2435 uno::RuntimeException)
2437 SwTextMarkupHelper aTextMarkupHelper( *GetTxtNode(), GetPortionData() );
2439 return aTextMarkupHelper.getTextMarkupCount( nTextMarkupType );
2442 /*accessibility::*/TextSegment SAL_CALL
2443 SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
2444 sal_Int32 nTextMarkupType )
2445 throw (lang::IndexOutOfBoundsException,
2446 lang::IllegalArgumentException,
2447 uno::RuntimeException)
2449 SwTextMarkupHelper aTextMarkupHelper( *GetTxtNode(), GetPortionData() );
2451 return aTextMarkupHelper.getTextMarkup( nTextMarkupIndex, nTextMarkupType );
2454 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
2455 SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
2456 sal_Int32 nTextMarkupType )
2457 throw (lang::IndexOutOfBoundsException,
2458 lang::IllegalArgumentException,
2459 uno::RuntimeException)
2461 // parameter checking
2462 const sal_Int32 nLength = GetString().getLength();
2463 if ( ! IsValidPosition( nCharIndex, nLength ) )
2465 throw lang::IndexOutOfBoundsException();
2468 SwTextMarkupHelper aTextMarkupHelper( *GetTxtNode(), GetPortionData() );
2470 return aTextMarkupHelper.getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
2472 // <--
2474 // --> OD 2008-05-29 #i89175#
2475 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
2476 throw (lang::IndexOutOfBoundsException,
2477 uno::RuntimeException)
2479 // parameter checking
2480 const sal_Int32 nLength = GetString().getLength();
2481 if ( ! IsValidPosition( nIndex, nLength ) )
2483 throw lang::IndexOutOfBoundsException();
2486 const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
2487 return nLineNo;
2490 /*accessibility::*/TextSegment SAL_CALL
2491 SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
2492 throw (lang::IndexOutOfBoundsException,
2493 uno::RuntimeException)
2495 // parameter checking
2496 if ( nLineNo < 0 ||
2497 nLineNo >= GetPortionData().GetLineCount() )
2499 throw lang::IndexOutOfBoundsException();
2502 Boundary aLineBound;
2503 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2505 /*accessibility::*/TextSegment aTextAtLine;
2506 const ::rtl::OUString rText = GetString();
2507 aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
2508 aLineBound.endPos - aLineBound.startPos );
2509 aTextAtLine.SegmentStart = aLineBound.startPos;
2510 aTextAtLine.SegmentEnd = aLineBound.endPos;
2512 return aTextAtLine;
2515 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
2516 throw (uno::RuntimeException)
2518 const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
2520 if ( nLineNoOfCaret >= 0 &&
2521 nLineNoOfCaret < GetPortionData().GetLineCount() )
2523 return getTextAtLineNumber( nLineNoOfCaret );
2526 return /*accessibility::*/TextSegment();
2529 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
2530 throw (uno::RuntimeException)
2532 const sal_Int32 nCaretPos = getCaretPosition();
2533 const sal_Int32 nLength = GetString().getLength();
2534 if ( !IsValidPosition( nCaretPos, nLength ) )
2536 return -1;
2539 sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
2541 // special handling for cursor positioned at end of text line via End key
2542 if ( nCaretPos != 0 )
2544 Boundary aLineBound;
2545 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2546 if ( nCaretPos == aLineBound.startPos )
2548 SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
2549 if ( pCrsrShell != 0 )
2551 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
2553 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect();
2554 // translate core coordinates into accessibility coordinates
2555 Window *pWin = GetWindow();
2556 CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2558 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
2560 SwRect aFrmLogBounds( GetBounds() ); // twip rel to doc root
2561 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
2562 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() );
2564 // convert into AWT Rectangle
2565 const awt::Rectangle aCursorRect( aScreenRect.Left(),
2566 aScreenRect.Top(),
2567 aScreenRect.GetWidth(),
2568 aScreenRect.GetHeight() );
2570 if ( aCharRect.X != aCursorRect.X ||
2571 aCharRect.Y != aCursorRect.Y )
2573 --nLineNo;
2579 return nLineNo;
2582 // <--