Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <txtfrm.hxx>
22 : #include <flyfrm.hxx>
23 : #include <ndtxt.hxx>
24 : #include <pam.hxx>
25 : #include <unotextrange.hxx>
26 : #include <unocrsrhelper.hxx>
27 : #include <crstate.hxx>
28 : #include <accmap.hxx>
29 : #include <fesh.hxx>
30 : #include <viewopt.hxx>
31 : #include <osl/mutex.hxx>
32 : #include <vcl/svapp.hxx>
33 : #include <vcl/window.hxx>
34 : #include <rtl/ustrbuf.hxx>
35 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
36 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
37 : #include <com/sun/star/accessibility/AccessibleTextType.hpp>
38 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
39 : #include <unotools/accessiblestatesethelper.hxx>
40 : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
41 : #include <com/sun/star/i18n/WordType.hpp>
42 : #include <com/sun/star/i18n/XBreakIterator.hpp>
43 : #include <com/sun/star/beans/UnknownPropertyException.hpp>
44 : #include <breakit.hxx>
45 : #include <accpara.hxx>
46 : #include <access.hrc>
47 : #include <accportions.hxx>
48 : #include <sfx2/viewsh.hxx> // for ExecuteAtViewShell(...)
49 : #include <sfx2/viewfrm.hxx> // for ExecuteAtViewShell(...)
50 : #include <sfx2/dispatch.hxx> // for ExecuteAtViewShell(...)
51 : #include <unotools/charclass.hxx> // for GetWordBoundary
52 : #include <unocrsr.hxx>
53 : #include <unoport.hxx>
54 : #include <doc.hxx>
55 : #include <crsskip.hxx>
56 : #include <txtatr.hxx>
57 : #include <acchyperlink.hxx>
58 : #include <acchypertextdata.hxx>
59 : #include <unotools/accessiblerelationsethelper.hxx>
60 : #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
61 : #include <comphelper/accessibletexthelper.hxx>
62 : #include <unomap.hxx>
63 : #include <unoprnms.hxx>
64 : #include <com/sun/star/text/WritingMode2.hpp>
65 : #include <editeng/brushitem.hxx>
66 : #include <viewimp.hxx>
67 : #include <boost/scoped_ptr.hpp>
68 : #include <textmarkuphelper.hxx>
69 : // #i10825#
70 : #include <parachangetrackinginfo.hxx>
71 : #include <com/sun/star/text/TextMarkupType.hpp>
72 : #include <comphelper/stlunosequence.hxx> // #i92233#
73 : #include <comphelper/servicehelper.hxx>
74 :
75 : #include <algorithm>
76 :
77 : using namespace ::com::sun::star;
78 : using namespace ::com::sun::star::accessibility;
79 :
80 : using beans::PropertyValue;
81 : using beans::XMultiPropertySet;
82 : using beans::UnknownPropertyException;
83 : using beans::PropertyState_DIRECT_VALUE;
84 :
85 : using std::max;
86 : using std::min;
87 : using std::sort;
88 :
89 : namespace com { namespace sun { namespace star {
90 : namespace text {
91 : class XText;
92 : }
93 : } } }
94 :
95 :
96 : const sal_Char sServiceName[] = "com.sun.star.text.AccessibleParagraphView";
97 : const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView";
98 : const xub_StrLen MAX_DESC_TEXT_LEN = 40;
99 116 : const SwTxtNode* SwAccessibleParagraph::GetTxtNode() const
100 : {
101 116 : const SwFrm* pFrm = GetFrm();
102 : OSL_ENSURE( pFrm->IsTxtFrm(), "The text frame has mutated!" );
103 :
104 116 : const SwTxtNode* pNode = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode();
105 : OSL_ENSURE( pNode != NULL, "A text frame without a text node." );
106 :
107 116 : return pNode;
108 : }
109 :
110 34 : OUString SwAccessibleParagraph::GetString()
111 : {
112 34 : return GetPortionData().GetAccessibleString();
113 : }
114 :
115 13 : OUString SwAccessibleParagraph::GetDescription()
116 : {
117 13 : return OUString(); // provide empty description for paragraphs
118 : }
119 :
120 75 : sal_Int32 SwAccessibleParagraph::GetCaretPos()
121 : {
122 75 : sal_Int32 nRet = -1;
123 :
124 : // get the selection's point, and test whether it's in our node
125 : // #i27301# - consider adjusted method signature
126 75 : SwPaM* pCaret = GetCursor( false ); // caret is first PaM in PaM-ring
127 :
128 75 : if( pCaret != NULL )
129 : {
130 74 : const SwTxtNode* pNode = GetTxtNode();
131 :
132 : // check whether the point points into 'our' node
133 74 : SwPosition* pPoint = pCaret->GetPoint();
134 74 : if( pNode->GetIndex() == pPoint->nNode.GetIndex() )
135 : {
136 : // same node? Then check whether it's also within 'our' part
137 : // of the paragraph
138 66 : sal_uInt16 nIndex = pPoint->nContent.GetIndex();
139 66 : if( GetPortionData().IsValidCorePosition( nIndex ) )
140 : {
141 : // Yes, it's us!
142 : // consider that cursor/caret is in front of the list label
143 66 : if ( pCaret->IsInFrontOfLabel() )
144 : {
145 0 : nRet = 0;
146 : }
147 : else
148 : {
149 66 : nRet = GetPortionData().GetAccessiblePosition( nIndex );
150 : }
151 :
152 : OSL_ENSURE( nRet >= 0, "invalid cursor?" );
153 : OSL_ENSURE( nRet <= GetPortionData().GetAccessibleString().
154 : getLength(), "invalid cursor?" );
155 : }
156 : // else: in this paragraph, but in different frame
157 : }
158 : // else: not in this paragraph
159 : }
160 : // else: no cursor -> no caret
161 :
162 75 : return nRet;
163 : }
164 :
165 0 : sal_Bool SwAccessibleParagraph::GetSelection(
166 : sal_Int32& nStart, sal_Int32& nEnd)
167 : {
168 0 : sal_Bool bRet = sal_False;
169 0 : nStart = -1;
170 0 : nEnd = -1;
171 :
172 : // get the selection, and test whether it affects our text node
173 0 : SwPaM* pCrsr = GetCursor( true ); // #i27301# - consider adjusted method signature
174 0 : if( pCrsr != NULL )
175 : {
176 : // get SwPosition for my node
177 0 : const SwTxtNode* pNode = GetTxtNode();
178 0 : sal_uLong nHere = pNode->GetIndex();
179 :
180 : // iterate over ring
181 0 : SwPaM* pRingStart = pCrsr;
182 0 : do
183 : {
184 : // ignore, if no mark
185 0 : if( pCrsr->HasMark() )
186 : {
187 : // check whether nHere is 'inside' pCrsr
188 0 : SwPosition* pStart = pCrsr->Start();
189 0 : sal_uLong nStartIndex = pStart->nNode.GetIndex();
190 0 : SwPosition* pEnd = pCrsr->End();
191 0 : sal_uLong nEndIndex = pEnd->nNode.GetIndex();
192 0 : if( ( nHere >= nStartIndex ) &&
193 : ( nHere <= nEndIndex ) )
194 : {
195 : // translate start and end positions
196 :
197 : // start position
198 0 : sal_Int32 nLocalStart = -1;
199 0 : if( nHere > nStartIndex )
200 : {
201 : // selection starts in previous node:
202 : // then our local selection starts with the paragraph
203 0 : nLocalStart = 0;
204 : }
205 : else
206 : {
207 : OSL_ENSURE( nHere == nStartIndex,
208 : "miscalculated index" );
209 :
210 : // selection starts in this node:
211 : // then check whether it's before or inside our part of
212 : // the paragraph, and if so, get the proper position
213 0 : sal_uInt16 nCoreStart = pStart->nContent.GetIndex();
214 0 : if( nCoreStart <
215 0 : GetPortionData().GetFirstValidCorePosition() )
216 : {
217 0 : nLocalStart = 0;
218 : }
219 0 : else if( nCoreStart <=
220 0 : GetPortionData().GetLastValidCorePosition() )
221 : {
222 : OSL_ENSURE(
223 : GetPortionData().IsValidCorePosition(
224 : nCoreStart ),
225 : "problem determining valid core position" );
226 :
227 : nLocalStart =
228 0 : GetPortionData().GetAccessiblePosition(
229 0 : nCoreStart );
230 : }
231 : }
232 :
233 : // end position
234 0 : sal_Int32 nLocalEnd = -1;
235 0 : if( nHere < nEndIndex )
236 : {
237 : // selection ends in following node:
238 : // then our local selection extends to the end
239 0 : nLocalEnd = GetPortionData().GetAccessibleString().
240 0 : getLength();
241 : }
242 : else
243 : {
244 : OSL_ENSURE( nHere == nEndIndex,
245 : "miscalculated index" );
246 :
247 : // selection ends in this node: then select everything
248 : // before our part of the node
249 0 : sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex();
250 0 : if( nCoreEnd >
251 0 : GetPortionData().GetLastValidCorePosition() )
252 : {
253 : // selection extends beyond out part of this para
254 0 : nLocalEnd = GetPortionData().GetAccessibleString().
255 0 : getLength();
256 : }
257 0 : else if( nCoreEnd >=
258 0 : GetPortionData().GetFirstValidCorePosition() )
259 : {
260 : // selection is inside our part of this para
261 : OSL_ENSURE(
262 : GetPortionData().IsValidCorePosition(
263 : nCoreEnd ),
264 : "problem determining valid core position" );
265 :
266 0 : nLocalEnd = GetPortionData().GetAccessiblePosition(
267 0 : nCoreEnd );
268 : }
269 : }
270 :
271 0 : if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
272 : {
273 0 : nStart = nLocalStart;
274 0 : nEnd = nLocalEnd;
275 0 : bRet = sal_True;
276 : }
277 : }
278 : // else: this PaM doesn't point to this paragraph
279 : }
280 : // else: this PaM is collapsed and doesn't select anything
281 :
282 : // next PaM in ring
283 0 : pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() );
284 : }
285 0 : while( !bRet && (pCrsr != pRingStart) );
286 : }
287 : // else: nocursor -> no selection
288 :
289 0 : return bRet;
290 : }
291 :
292 : // #i27301# - new parameter <_bForSelection>
293 87 : SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection )
294 : {
295 : // get the cursor shell; if we don't have any, we don't have a
296 : // cursor/selection either
297 87 : SwPaM* pCrsr = NULL;
298 87 : SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
299 : // #i27301# - if cursor is retrieved for selection, the cursors for
300 : // a table selection has to be returned.
301 172 : if ( pCrsrShell != NULL &&
302 87 : ( _bForSelection || !pCrsrShell->IsTableMode() ) )
303 : {
304 85 : SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell )
305 85 : ? static_cast< SwFEShell * >( pCrsrShell ) : 0;
306 255 : if( !pFESh ||
307 170 : !(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) )
308 : {
309 : // get the selection, and test whether it affects our text node
310 85 : pCrsr = pCrsrShell->GetCrsr( sal_False /* ??? */ );
311 : }
312 : }
313 :
314 87 : return pCrsr;
315 : }
316 :
317 31 : sal_Bool SwAccessibleParagraph::IsHeading() const
318 : {
319 31 : const SwTxtNode *pTxtNd = GetTxtNode();
320 31 : return pTxtNd->IsOutline();
321 : }
322 :
323 11 : void SwAccessibleParagraph::GetStates(
324 : ::utl::AccessibleStateSetHelper& rStateSet )
325 : {
326 11 : SwAccessibleContext::GetStates( rStateSet );
327 :
328 : // MULTILINE
329 11 : rStateSet.AddState( AccessibleStateType::MULTI_LINE );
330 :
331 : // MULTISELECTABLE
332 11 : SwCrsrShell *pCrsrSh = GetCrsrShell();
333 11 : if( pCrsrSh )
334 11 : rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
335 :
336 : // FOCUSABLE
337 11 : if( pCrsrSh )
338 11 : rStateSet.AddState( AccessibleStateType::FOCUSABLE );
339 :
340 : // FOCUSED (simulates node index of cursor)
341 11 : SwPaM* pCaret = GetCursor( false ); // #i27301# - consider adjusted method signature
342 11 : const SwTxtNode* pTxtNd = GetTxtNode();
343 31 : if( pCaret != 0 && pTxtNd != 0 &&
344 30 : pTxtNd->GetIndex() == pCaret->GetPoint()->nNode.GetIndex() &&
345 9 : nOldCaretPos != -1)
346 : {
347 9 : Window *pWin = GetWindow();
348 9 : if( pWin && pWin->HasFocus() )
349 9 : rStateSet.AddState( AccessibleStateType::FOCUSED );
350 9 : ::rtl::Reference < SwAccessibleContext > xThis( this );
351 9 : GetMap()->SetCursorContext( xThis );
352 : }
353 11 : }
354 :
355 14 : void SwAccessibleParagraph::_InvalidateContent( sal_Bool bVisibleDataFired )
356 : {
357 14 : OUString sOldText( GetString() );
358 :
359 14 : ClearPortionData();
360 :
361 28 : const OUString& rText = GetString();
362 :
363 14 : if( rText != sOldText )
364 : {
365 : // The text is changed
366 0 : AccessibleEventObject aEvent;
367 0 : aEvent.EventId = AccessibleEventId::TEXT_CHANGED;
368 :
369 : // determine exact changes between sOldText and rText
370 : comphelper::OCommonAccessibleText::implInitTextChangedEvent(
371 : sOldText, rText,
372 0 : aEvent.OldValue, aEvent.NewValue );
373 :
374 0 : FireAccessibleEvent( aEvent );
375 : }
376 14 : else if( !bVisibleDataFired )
377 : {
378 0 : FireVisibleDataEvent();
379 : }
380 :
381 14 : sal_Bool bNewIsHeading = IsHeading();
382 : sal_Bool bOldIsHeading;
383 : {
384 14 : osl::MutexGuard aGuard( aMutex );
385 14 : bOldIsHeading = bIsHeading;
386 14 : if( bIsHeading != bNewIsHeading )
387 0 : bIsHeading = bNewIsHeading;
388 : }
389 :
390 14 : if( bNewIsHeading != bOldIsHeading || rText != sOldText )
391 : {
392 0 : OUString sNewDesc( GetDescription() );
393 0 : OUString sOldDesc;
394 : {
395 0 : osl::MutexGuard aGuard( aMutex );
396 0 : sOldDesc = sDesc;
397 0 : if( sDesc != sNewDesc )
398 0 : sDesc = sNewDesc;
399 : }
400 :
401 0 : if( sNewDesc != sOldDesc )
402 : {
403 : // The text is changed
404 0 : AccessibleEventObject aEvent;
405 0 : aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
406 0 : aEvent.OldValue <<= sOldDesc;
407 0 : aEvent.NewValue <<= sNewDesc;
408 :
409 0 : FireAccessibleEvent( aEvent );
410 0 : }
411 14 : }
412 14 : }
413 :
414 58 : void SwAccessibleParagraph::_InvalidateCursorPos()
415 : {
416 : // The text is changed
417 58 : sal_Int32 nNew = GetCaretPos();
418 : sal_Int32 nOld;
419 : {
420 58 : osl::MutexGuard aGuard( aMutex );
421 58 : nOld = nOldCaretPos;
422 58 : nOldCaretPos = nNew;
423 : }
424 58 : if( -1 != nNew )
425 : {
426 : // remember that object as the one that has the caret. This is
427 : // necessary to notify that object if the cursor leaves it.
428 57 : ::rtl::Reference < SwAccessibleContext > xThis( this );
429 57 : GetMap()->SetCursorContext( xThis );
430 : }
431 :
432 58 : Window *pWin = GetWindow();
433 58 : if( nOld != nNew )
434 : {
435 : // The cursor's node position is simulated by the focus!
436 3 : if( pWin && pWin->HasFocus() && -1 == nOld )
437 2 : FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True );
438 :
439 3 : AccessibleEventObject aEvent;
440 3 : aEvent.EventId = AccessibleEventId::CARET_CHANGED;
441 3 : aEvent.OldValue <<= nOld;
442 3 : aEvent.NewValue <<= nNew;
443 :
444 3 : FireAccessibleEvent( aEvent );
445 :
446 3 : if( pWin && pWin->HasFocus() && -1 == nNew )
447 1 : FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_False );
448 : }
449 58 : }
450 :
451 9 : void SwAccessibleParagraph::_InvalidateFocus()
452 : {
453 9 : Window *pWin = GetWindow();
454 9 : if( pWin )
455 : {
456 : sal_Int32 nPos;
457 : {
458 9 : osl::MutexGuard aGuard( aMutex );
459 9 : nPos = nOldCaretPos;
460 : }
461 : OSL_ENSURE( nPos != -1, "focus object should be selected" );
462 :
463 : FireStateChangedEvent( AccessibleStateType::FOCUSED,
464 9 : pWin->HasFocus() && nPos != -1 );
465 : }
466 9 : }
467 :
468 17 : SwAccessibleParagraph::SwAccessibleParagraph(
469 : SwAccessibleMap& rInitMap,
470 : const SwTxtFrm& rTxtFrm )
471 17 : : SwClient( const_cast<SwTxtNode*>(rTxtFrm.GetTxtNode()) ) // #i108125#
472 : , SwAccessibleContext( &rInitMap, AccessibleRole::PARAGRAPH, &rTxtFrm )
473 : , sDesc()
474 : , pPortionData( NULL )
475 : , pHyperTextData( NULL )
476 : , nOldCaretPos( -1 )
477 : , bIsHeading( sal_False )
478 : , aSelectionHelper( *this )
479 17 : , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTxtFrm ) ) // #i108125#
480 : {
481 17 : SolarMutexGuard aGuard;
482 :
483 17 : bIsHeading = IsHeading();
484 17 : SetName( OUString() ); // set an empty accessibility name for paragraphs
485 :
486 : // If this object has the focus, then it is remembered by the map itself.
487 17 : nOldCaretPos = GetCaretPos();
488 17 : }
489 :
490 51 : SwAccessibleParagraph::~SwAccessibleParagraph()
491 : {
492 17 : SolarMutexGuard aGuard;
493 :
494 17 : delete pPortionData;
495 17 : delete pHyperTextData;
496 17 : delete mpParaChangeTrackInfo; // #i108125#
497 34 : }
498 :
499 18 : sal_Bool SwAccessibleParagraph::HasCursor()
500 : {
501 18 : osl::MutexGuard aGuard( aMutex );
502 18 : return nOldCaretPos != -1;
503 : }
504 :
505 28 : void SwAccessibleParagraph::UpdatePortionData()
506 : throw( uno::RuntimeException )
507 : {
508 : // obtain the text frame
509 : OSL_ENSURE( GetFrm() != NULL, "The text frame has vanished!" );
510 : OSL_ENSURE( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
511 28 : const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
512 :
513 : // build new portion data
514 28 : delete pPortionData;
515 : pPortionData = new SwAccessiblePortionData(
516 28 : pFrm->GetTxtNode(), GetMap()->GetShell()->GetViewOptions() );
517 28 : pFrm->VisitPortions( *pPortionData );
518 :
519 : OSL_ENSURE( pPortionData != NULL, "UpdatePortionData() failed" );
520 28 : }
521 :
522 14 : void SwAccessibleParagraph::ClearPortionData()
523 : {
524 14 : delete pPortionData;
525 14 : pPortionData = NULL;
526 :
527 14 : delete pHyperTextData;
528 14 : pHyperTextData = 0;
529 14 : }
530 :
531 0 : void SwAccessibleParagraph::ExecuteAtViewShell( sal_uInt16 nSlot )
532 : {
533 : OSL_ENSURE( GetMap() != NULL, "no map?" );
534 0 : ViewShell* pViewShell = GetMap()->GetShell();
535 :
536 : OSL_ENSURE( pViewShell != NULL, "View shell expected!" );
537 0 : SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell();
538 :
539 : OSL_ENSURE( pSfxShell != NULL, "SfxViewShell shell expected!" );
540 0 : if( !pSfxShell )
541 0 : return;
542 :
543 0 : SfxViewFrame *pFrame = pSfxShell->GetViewFrame();
544 : OSL_ENSURE( pFrame != NULL, "View frame expected!" );
545 0 : if( !pFrame )
546 0 : return;
547 :
548 0 : SfxDispatcher *pDispatcher = pFrame->GetDispatcher();
549 : OSL_ENSURE( pDispatcher != NULL, "Dispatcher expected!" );
550 0 : if( !pDispatcher )
551 0 : return;
552 :
553 0 : pDispatcher->Execute( nSlot );
554 : }
555 :
556 0 : SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion(
557 : sal_Int32 nStartIndex,
558 : sal_Int32 nEndIndex )
559 : {
560 : OSL_ENSURE( (IsValidChar(nStartIndex, GetString().getLength()) &&
561 : (nEndIndex == -1)) ||
562 : IsValidRange(nStartIndex, nEndIndex, GetString().getLength()),
563 : "please check parameters before calling this method" );
564 :
565 0 : sal_uInt16 nStart = GetPortionData().GetModelPosition( nStartIndex );
566 : sal_uInt16 nEnd = (nEndIndex == -1) ? (nStart + 1) :
567 0 : GetPortionData().GetModelPosition( nEndIndex );
568 :
569 : // create UNO cursor
570 0 : SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() );
571 0 : SwIndex aIndex( pTxtNode, nStart );
572 0 : SwPosition aStartPos( *pTxtNode, aIndex );
573 0 : SwUnoCrsr* pUnoCursor = pTxtNode->GetDoc()->CreateUnoCrsr( aStartPos );
574 0 : pUnoCursor->SetMark();
575 0 : pUnoCursor->GetMark()->nContent = nEnd;
576 :
577 : // create a (dummy) text portion to be returned
578 0 : uno::Reference<text::XText> aEmpty;
579 : SwXTextPortion* pPortion =
580 0 : new SwXTextPortion ( pUnoCursor, aEmpty, PORTION_TEXT);
581 0 : delete pUnoCursor;
582 :
583 0 : return pPortion;
584 : }
585 :
586 : // range checking for parameter
587 :
588 0 : sal_Bool SwAccessibleParagraph::IsValidChar(
589 : sal_Int32 nPos, sal_Int32 nLength)
590 : {
591 0 : return (nPos >= 0) && (nPos < nLength);
592 : }
593 :
594 0 : sal_Bool SwAccessibleParagraph::IsValidPosition(
595 : sal_Int32 nPos, sal_Int32 nLength)
596 : {
597 0 : return (nPos >= 0) && (nPos <= nLength);
598 : }
599 :
600 0 : sal_Bool SwAccessibleParagraph::IsValidRange(
601 : sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength)
602 : {
603 0 : return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength);
604 : }
605 :
606 : // text boundaries
607 :
608 0 : sal_Bool SwAccessibleParagraph::GetCharBoundary(
609 : i18n::Boundary& rBound,
610 : const OUString&,
611 : sal_Int32 nPos )
612 : {
613 0 : rBound.startPos = nPos;
614 0 : rBound.endPos = nPos+1;
615 0 : return sal_True;
616 : }
617 :
618 0 : sal_Bool SwAccessibleParagraph::GetWordBoundary(
619 : i18n::Boundary& rBound,
620 : const OUString& rText,
621 : sal_Int32 nPos )
622 : {
623 0 : sal_Bool bRet = sal_False;
624 :
625 : // now ask the Break-Iterator for the word
626 : OSL_ENSURE( g_pBreakIt != NULL, "We always need a break." );
627 : OSL_ENSURE( g_pBreakIt->GetBreakIter().is(), "No break-iterator." );
628 0 : if( g_pBreakIt->GetBreakIter().is() )
629 : {
630 : // get locale for this position
631 0 : sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos );
632 : lang::Locale aLocale = g_pBreakIt->GetLocale(
633 0 : GetTxtNode()->GetLang( nModelPos ) );
634 :
635 : // which type of word are we interested in?
636 : // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.)
637 0 : const sal_uInt16 nWordType = i18n::WordType::ANY_WORD;
638 :
639 : // get word boundary, as the Break-Iterator sees fit.
640 0 : rBound = g_pBreakIt->GetBreakIter()->getWordBoundary(
641 0 : rText, nPos, aLocale, nWordType, sal_True );
642 :
643 : // It's a word if the first character is an alpha-numeric character.
644 0 : bRet = GetAppCharClass().isLetterNumeric(
645 0 : OUString(rText[rBound.startPos]) );
646 : }
647 : else
648 : {
649 : // no break Iterator -> no word
650 0 : rBound.startPos = nPos;
651 0 : rBound.endPos = nPos;
652 : }
653 :
654 0 : return bRet;
655 : }
656 :
657 0 : sal_Bool SwAccessibleParagraph::GetSentenceBoundary(
658 : i18n::Boundary& rBound,
659 : const OUString&,
660 : sal_Int32 nPos )
661 : {
662 0 : GetPortionData().GetSentenceBoundary( rBound, nPos );
663 0 : return sal_True;
664 : }
665 :
666 0 : sal_Bool SwAccessibleParagraph::GetLineBoundary(
667 : i18n::Boundary& rBound,
668 : const OUString& rText,
669 : sal_Int32 nPos )
670 : {
671 0 : if( rText.getLength() == nPos )
672 0 : GetPortionData().GetLastLineBoundary( rBound );
673 : else
674 0 : GetPortionData().GetLineBoundary( rBound, nPos );
675 0 : return sal_True;
676 : }
677 :
678 0 : sal_Bool SwAccessibleParagraph::GetParagraphBoundary(
679 : i18n::Boundary& rBound,
680 : const OUString& rText,
681 : sal_Int32 )
682 : {
683 0 : rBound.startPos = 0;
684 0 : rBound.endPos = rText.getLength();
685 0 : return sal_True;
686 : }
687 :
688 0 : sal_Bool SwAccessibleParagraph::GetAttributeBoundary(
689 : i18n::Boundary& rBound,
690 : const OUString&,
691 : sal_Int32 nPos )
692 : {
693 0 : GetPortionData().GetAttributeBoundary( rBound, nPos );
694 0 : return sal_True;
695 : }
696 :
697 0 : sal_Bool SwAccessibleParagraph::GetGlyphBoundary(
698 : i18n::Boundary& rBound,
699 : const OUString& rText,
700 : sal_Int32 nPos )
701 : {
702 0 : sal_Bool bRet = sal_False;
703 :
704 : // ask the Break-Iterator for the glyph by moving one cell
705 : // forward, and then one cell back
706 : OSL_ENSURE( g_pBreakIt != NULL, "We always need a break." );
707 : OSL_ENSURE( g_pBreakIt->GetBreakIter().is(), "No break-iterator." );
708 0 : if( g_pBreakIt->GetBreakIter().is() )
709 : {
710 : // get locale for this position
711 0 : sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos );
712 : lang::Locale aLocale = g_pBreakIt->GetLocale(
713 0 : GetTxtNode()->GetLang( nModelPos ) );
714 :
715 : // get word boundary, as the Break-Iterator sees fit.
716 0 : const sal_uInt16 nIterMode = i18n::CharacterIteratorMode::SKIPCELL;
717 0 : sal_Int32 nDone = 0;
718 0 : rBound.endPos = g_pBreakIt->GetBreakIter()->nextCharacters(
719 0 : rText, nPos, aLocale, nIterMode, 1, nDone );
720 0 : rBound.startPos = g_pBreakIt->GetBreakIter()->previousCharacters(
721 0 : rText, rBound.endPos, aLocale, nIterMode, 1, nDone );
722 0 : bRet = ((rBound.startPos <= nPos) && (nPos <= rBound.endPos));
723 : OSL_ENSURE( rBound.startPos <= nPos, "start pos too high" );
724 0 : OSL_ENSURE( rBound.endPos >= nPos, "end pos too low" );
725 : }
726 : else
727 : {
728 : // no break Iterator -> no glyph
729 0 : rBound.startPos = nPos;
730 0 : rBound.endPos = nPos;
731 : }
732 :
733 0 : return bRet;
734 : }
735 :
736 :
737 0 : sal_Bool SwAccessibleParagraph::GetTextBoundary(
738 : i18n::Boundary& rBound,
739 : const OUString& rText,
740 : sal_Int32 nPos,
741 : sal_Int16 nTextType )
742 : throw (
743 : lang::IndexOutOfBoundsException,
744 : lang::IllegalArgumentException,
745 : uno::RuntimeException)
746 : {
747 : // error checking
748 0 : if( !( AccessibleTextType::LINE == nTextType
749 0 : ? IsValidPosition( nPos, rText.getLength() )
750 0 : : IsValidChar( nPos, rText.getLength() ) ) )
751 0 : throw lang::IndexOutOfBoundsException();
752 :
753 : sal_Bool bRet;
754 :
755 0 : switch( nTextType )
756 : {
757 : case AccessibleTextType::WORD:
758 0 : bRet = GetWordBoundary( rBound, rText, nPos );
759 0 : break;
760 :
761 : case AccessibleTextType::SENTENCE:
762 0 : bRet = GetSentenceBoundary( rBound, rText, nPos );
763 0 : break;
764 :
765 : case AccessibleTextType::PARAGRAPH:
766 0 : bRet = GetParagraphBoundary( rBound, rText, nPos );
767 0 : break;
768 :
769 : case AccessibleTextType::CHARACTER:
770 0 : bRet = GetCharBoundary( rBound, rText, nPos );
771 0 : break;
772 :
773 : case AccessibleTextType::LINE:
774 0 : bRet = GetLineBoundary( rBound, rText, nPos );
775 0 : break;
776 :
777 : case AccessibleTextType::ATTRIBUTE_RUN:
778 0 : bRet = GetAttributeBoundary( rBound, rText, nPos );
779 0 : break;
780 :
781 : case AccessibleTextType::GLYPH:
782 0 : bRet = GetGlyphBoundary( rBound, rText, nPos );
783 0 : break;
784 :
785 : default:
786 0 : throw lang::IllegalArgumentException( );
787 : }
788 :
789 0 : return bRet;
790 : }
791 :
792 13 : OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void)
793 : throw (uno::RuntimeException)
794 : {
795 13 : SolarMutexGuard aGuard;
796 :
797 13 : CHECK_FOR_DEFUNC( XAccessibleContext );
798 :
799 26 : osl::MutexGuard aGuard2( aMutex );
800 13 : if( sDesc.isEmpty() )
801 13 : sDesc = GetDescription();
802 :
803 26 : return sDesc;
804 : }
805 :
806 1 : lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void)
807 : throw (IllegalAccessibleComponentStateException, uno::RuntimeException)
808 : {
809 1 : SolarMutexGuard aGuard;
810 :
811 1 : SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() );
812 1 : if( !pTxtFrm )
813 : {
814 0 : THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" );
815 : }
816 :
817 1 : const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode();
818 1 : lang::Locale aLoc( g_pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) );
819 :
820 1 : return aLoc;
821 : }
822 :
823 : // #i27138# - paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
824 3 : uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
825 : throw ( uno::RuntimeException )
826 : {
827 3 : SolarMutexGuard aGuard;
828 3 : CHECK_FOR_DEFUNC( XAccessibleContext );
829 :
830 3 : utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
831 :
832 3 : const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm());
833 : OSL_ENSURE( pTxtFrm,
834 : "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame");
835 3 : if ( pTxtFrm )
836 : {
837 3 : const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) );
838 3 : if ( pPrevCntFrm )
839 : {
840 1 : uno::Sequence< uno::Reference<XInterface> > aSequence(1);
841 1 : aSequence[0] = GetMap()->GetContext( pPrevCntFrm );
842 : AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
843 2 : aSequence );
844 2 : pHelper->AddRelation( aAccRel );
845 : }
846 :
847 3 : const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) );
848 3 : if ( pNextCntFrm )
849 : {
850 2 : uno::Sequence< uno::Reference<XInterface> > aSequence(1);
851 2 : aSequence[0] = GetMap()->GetContext( pNextCntFrm );
852 : AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
853 4 : aSequence );
854 4 : pHelper->AddRelation( aAccRel );
855 : }
856 : }
857 :
858 3 : return pHelper;
859 : }
860 :
861 1 : void SAL_CALL SwAccessibleParagraph::grabFocus()
862 : throw (uno::RuntimeException)
863 : {
864 1 : SolarMutexGuard aGuard;
865 :
866 1 : CHECK_FOR_DEFUNC( XAccessibleContext );
867 :
868 : // get cursor shell
869 1 : SwCrsrShell *pCrsrSh = GetCrsrShell();
870 1 : SwPaM *pCrsr = GetCursor( false ); // #i27301# - consider new method signature
871 1 : const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
872 1 : const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode();
873 :
874 1 : if( pCrsrSh != 0 && pTxtNd != 0 &&
875 1 : ( pCrsr == 0 ||
876 2 : pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() ||
877 1 : !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) )
878 : {
879 : // create pam for selection
880 : SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ),
881 0 : pTxtFrm->GetOfst() );
882 0 : SwPosition aStartPos( *pTxtNd, aIndex );
883 0 : SwPaM aPaM( aStartPos );
884 :
885 : // set PaM at cursor shell
886 0 : Select( aPaM );
887 :
888 : }
889 :
890 : // ->#i13955#
891 1 : Window * pWindow = GetWindow();
892 :
893 1 : if (pWindow != NULL)
894 1 : pWindow->GrabFocus();
895 : // <-#i13955#
896 1 : }
897 :
898 : // #i71385#
899 2 : static bool lcl_GetBackgroundColor( Color & rColor,
900 : const SwFrm* pFrm,
901 : SwCrsrShell* pCrsrSh )
902 : {
903 2 : const SvxBrushItem* pBackgrdBrush = 0;
904 2 : const XFillStyleItem* pFillStyleItem = 0;
905 2 : const XFillGradientItem* pFillGradientItem = 0;
906 2 : const Color* pSectionTOXColor = 0;
907 2 : SwRect aDummyRect;
908 4 : if ( pFrm &&
909 2 : pFrm->GetBackgroundBrush( pBackgrdBrush, pFillStyleItem, pFillGradientItem, pSectionTOXColor, aDummyRect, false ) )
910 : {
911 0 : if ( pSectionTOXColor )
912 : {
913 0 : rColor = *pSectionTOXColor;
914 0 : return true;
915 : }
916 : else
917 : {
918 0 : rColor = pBackgrdBrush->GetColor();
919 0 : return true;
920 : }
921 : }
922 2 : else if ( pCrsrSh )
923 : {
924 2 : rColor = pCrsrSh->Imp()->GetRetoucheColor();
925 2 : return true;
926 : }
927 :
928 0 : return false;
929 : }
930 :
931 1 : sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground()
932 : throw (uno::RuntimeException)
933 : {
934 1 : Color aBackgroundCol;
935 :
936 1 : if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
937 : {
938 1 : if ( aBackgroundCol.IsDark() )
939 : {
940 0 : return COL_WHITE;
941 : }
942 : else
943 : {
944 1 : return COL_BLACK;
945 : }
946 : }
947 :
948 0 : return SwAccessibleContext::getForeground();
949 : }
950 :
951 1 : sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
952 : throw (uno::RuntimeException)
953 : {
954 1 : Color aBackgroundCol;
955 :
956 1 : if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) )
957 : {
958 1 : return aBackgroundCol.GetColor();
959 : }
960 :
961 0 : return SwAccessibleContext::getBackground();
962 : }
963 :
964 3 : OUString SAL_CALL SwAccessibleParagraph::getImplementationName()
965 : throw( uno::RuntimeException )
966 : {
967 3 : return OUString(sImplementationName);
968 : }
969 :
970 0 : sal_Bool SAL_CALL SwAccessibleParagraph::supportsService(
971 : const OUString& sTestServiceName)
972 : throw (uno::RuntimeException)
973 : {
974 : return sTestServiceName.equalsAsciiL( sServiceName,
975 0 : sizeof(sServiceName)-1 ) ||
976 : sTestServiceName.equalsAsciiL( sAccessibleServiceName,
977 0 : sizeof(sAccessibleServiceName)-1 );
978 : }
979 :
980 0 : uno::Sequence< OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames()
981 : throw( uno::RuntimeException )
982 : {
983 0 : uno::Sequence< OUString > aRet(2);
984 0 : OUString* pArray = aRet.getArray();
985 0 : pArray[0] = OUString( sServiceName );
986 0 : pArray[1] = OUString( sAccessibleServiceName );
987 0 : return aRet;
988 : }
989 :
990 : // XInterface
991 :
992 467 : uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType )
993 : throw (uno::RuntimeException)
994 : {
995 467 : uno::Any aRet;
996 467 : if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) )
997 : {
998 3 : uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity
999 3 : aRet <<= aAccText;
1000 : }
1001 464 : else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) )
1002 : {
1003 0 : uno::Reference<XAccessibleEditableText> aAccEditText = this;
1004 0 : aRet <<= aAccEditText;
1005 : }
1006 464 : else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) )
1007 : {
1008 9 : uno::Reference<XAccessibleSelection> aAccSel = this;
1009 9 : aRet <<= aAccSel;
1010 : }
1011 455 : else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) )
1012 : {
1013 0 : uno::Reference<XAccessibleHypertext> aAccHyp = this;
1014 0 : aRet <<= aAccHyp;
1015 : }
1016 : // #i63870#
1017 : // add interface com::sun:star:accessibility::XAccessibleTextAttributes
1018 455 : else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) )
1019 : {
1020 0 : uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
1021 0 : aRet <<= aAccTextAttr;
1022 : }
1023 : // #i89175#
1024 : // add interface com::sun:star:accessibility::XAccessibleTextMarkup
1025 455 : else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) )
1026 : {
1027 0 : uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this;
1028 0 : aRet <<= aAccTextMarkup;
1029 : }
1030 : // add interface com::sun:star:accessibility::XAccessibleMultiLineText
1031 455 : else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) )
1032 : {
1033 0 : uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this;
1034 0 : aRet <<= aAccMultiLineText;
1035 : }
1036 : else
1037 : {
1038 455 : aRet = SwAccessibleContext::queryInterface(rType);
1039 : }
1040 :
1041 467 : return aRet;
1042 : }
1043 :
1044 : // XTypeProvider
1045 0 : uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException)
1046 : {
1047 0 : uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
1048 :
1049 0 : sal_Int32 nIndex = aTypes.getLength();
1050 : // #i63870# - add type accessibility::XAccessibleTextAttributes
1051 : // #i89175# - add type accessibility::XAccessibleTextMarkup and
1052 : // accessibility::XAccessibleMultiLineText
1053 0 : aTypes.realloc( nIndex + 6 );
1054 :
1055 0 : uno::Type* pTypes = aTypes.getArray();
1056 0 : pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) );
1057 0 : pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) );
1058 0 : pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) );
1059 0 : pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) );
1060 0 : pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) );
1061 0 : pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) );
1062 :
1063 0 : return aTypes;
1064 : }
1065 :
1066 : namespace
1067 : {
1068 : class theSwAccessibleParagraphImplementationId : public rtl::Static< UnoTunnelIdInit, theSwAccessibleParagraphImplementationId > {};
1069 : }
1070 :
1071 0 : uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId()
1072 : throw(uno::RuntimeException)
1073 : {
1074 0 : return theSwAccessibleParagraphImplementationId::get().getSeq();
1075 : }
1076 :
1077 : // XAccesibleText
1078 :
1079 0 : sal_Int32 SwAccessibleParagraph::getCaretPosition()
1080 : throw (uno::RuntimeException)
1081 : {
1082 0 : SolarMutexGuard aGuard;
1083 :
1084 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1085 :
1086 0 : sal_Int32 nRet = GetCaretPos();
1087 : {
1088 0 : osl::MutexGuard aOldCaretPosGuard( aMutex );
1089 : OSL_ENSURE( nRet == nOldCaretPos, "caret pos out of sync" );
1090 0 : nOldCaretPos = nRet;
1091 : }
1092 0 : if( -1 != nRet )
1093 : {
1094 0 : ::rtl::Reference < SwAccessibleContext > xThis( this );
1095 0 : GetMap()->SetCursorContext( xThis );
1096 : }
1097 :
1098 0 : return nRet;
1099 : }
1100 :
1101 0 : sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
1102 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1103 : {
1104 0 : SolarMutexGuard aGuard;
1105 :
1106 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1107 :
1108 : // parameter checking
1109 0 : sal_Int32 nLength = GetString().getLength();
1110 0 : if ( ! IsValidPosition( nIndex, nLength ) )
1111 : {
1112 0 : throw lang::IndexOutOfBoundsException();
1113 : }
1114 :
1115 0 : sal_Bool bRet = sal_False;
1116 :
1117 : // get cursor shell
1118 0 : SwCrsrShell* pCrsrShell = GetCrsrShell();
1119 0 : if( pCrsrShell != NULL )
1120 : {
1121 : // create pam for selection
1122 0 : SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1123 0 : SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex));
1124 0 : SwPosition aStartPos( *pNode, aIndex );
1125 0 : SwPaM aPaM( aStartPos );
1126 :
1127 : // set PaM at cursor shell
1128 0 : bRet = Select( aPaM );
1129 : }
1130 :
1131 0 : return bRet;
1132 : }
1133 :
1134 0 : sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex )
1135 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1136 : {
1137 0 : SolarMutexGuard aGuard;
1138 :
1139 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1140 :
1141 0 : OUString sText( GetString() );
1142 :
1143 : // return character (if valid)
1144 0 : if( IsValidChar(nIndex, sText.getLength() ) )
1145 : {
1146 0 : return sText.getStr()[nIndex];
1147 : }
1148 : else
1149 0 : throw lang::IndexOutOfBoundsException();
1150 : }
1151 :
1152 : // #i63870# - re-implement method on behalf of methods
1153 : // <_getDefaultAttributesImpl(..)> and <_getRunAttributesImpl(..)>
1154 0 : uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes(
1155 : sal_Int32 nIndex,
1156 : const uno::Sequence< OUString >& aRequestedAttributes )
1157 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1158 : {
1159 :
1160 0 : SolarMutexGuard aGuard;
1161 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1162 :
1163 0 : const OUString& rText = GetString();
1164 :
1165 0 : if( ! IsValidChar( nIndex, rText.getLength() ) )
1166 0 : throw lang::IndexOutOfBoundsException();
1167 :
1168 : // retrieve default character attributes
1169 0 : tAccParaPropValMap aDefAttrSeq;
1170 0 : _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true );
1171 :
1172 : // retrieved run character attributes
1173 0 : tAccParaPropValMap aRunAttrSeq;
1174 0 : _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1175 :
1176 : // merge default and run attributes
1177 0 : uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() );
1178 0 : PropertyValue* pValues = aValues.getArray();
1179 0 : sal_Int32 i = 0;
1180 0 : for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin();
1181 0 : aDefIter != aDefAttrSeq.end();
1182 : ++aDefIter )
1183 : {
1184 : tAccParaPropValMap::const_iterator aRunIter =
1185 0 : aRunAttrSeq.find( aDefIter->first );
1186 0 : if ( aRunIter != aRunAttrSeq.end() )
1187 : {
1188 0 : pValues[i] = aRunIter->second;
1189 : }
1190 : else
1191 : {
1192 0 : pValues[i] = aDefIter->second;
1193 : }
1194 0 : ++i;
1195 : }
1196 :
1197 0 : return aValues;
1198 : }
1199 :
1200 : // #i63870#
1201 0 : void SwAccessibleParagraph::_getDefaultAttributesImpl(
1202 : const uno::Sequence< OUString >& aRequestedAttributes,
1203 : tAccParaPropValMap& rDefAttrSeq,
1204 : const bool bOnlyCharAttrs )
1205 : {
1206 : // retrieve default attributes
1207 0 : const SwTxtNode* pTxtNode( GetTxtNode() );
1208 0 : ::boost::scoped_ptr<SfxItemSet> pSet;
1209 0 : if ( !bOnlyCharAttrs )
1210 : {
1211 0 : pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1212 : RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1213 : RES_PARATR_BEGIN, RES_PARATR_END - 1,
1214 : RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1215 0 : 0 ) );
1216 : }
1217 : else
1218 : {
1219 0 : pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1220 : RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1221 0 : 0 ) );
1222 : }
1223 : // #i82637# - From the perspective of the a11y API the default character
1224 : // attributes are the character attributes, which are set at the paragraph style
1225 : // of the paragraph. The character attributes set at the automatic paragraph
1226 : // style of the paragraph are treated as run attributes.
1227 : // pTxtNode->SwCntntNode::GetAttr( *pSet );
1228 : // get default paragraph attributes, if needed, and merge these into <pSet>
1229 0 : if ( !bOnlyCharAttrs )
1230 : {
1231 0 : SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1232 : RES_PARATR_BEGIN, RES_PARATR_END - 1,
1233 : RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
1234 0 : 0 );
1235 0 : pTxtNode->SwCntntNode::GetAttr( aParaSet );
1236 0 : pSet->Put( aParaSet );
1237 : }
1238 : // get default character attributes and merge these into <pSet>
1239 : OSL_ENSURE( pTxtNode->GetTxtColl(),
1240 : "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" );
1241 0 : if ( pTxtNode->GetTxtColl() )
1242 : {
1243 0 : SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
1244 : RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1245 0 : 0 );
1246 0 : aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() );
1247 0 : pSet->Put( aCharSet );
1248 : }
1249 :
1250 : // build-up sequence containing the run attributes <rDefAttrSeq>
1251 0 : tAccParaPropValMap aDefAttrSeq;
1252 : {
1253 : const SfxItemPropertyMap& rPropMap =
1254 0 : aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1255 0 : PropertyEntryVector_t aPropertyEntries = rPropMap.getPropertyEntries();
1256 0 : PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1257 0 : while ( aPropIt != aPropertyEntries.end() )
1258 : {
1259 0 : const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID );
1260 0 : if ( pItem )
1261 : {
1262 0 : uno::Any aVal;
1263 0 : pItem->QueryValue( aVal, aPropIt->nMemberId );
1264 :
1265 0 : PropertyValue rPropVal;
1266 0 : rPropVal.Name = aPropIt->sName;
1267 0 : rPropVal.Value = aVal;
1268 0 : rPropVal.Handle = -1;
1269 0 : rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1270 :
1271 0 : aDefAttrSeq[rPropVal.Name] = rPropVal;
1272 : }
1273 0 : ++aPropIt;
1274 : }
1275 :
1276 : // #i72800#
1277 : // add property value entry for the paragraph style
1278 0 : if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() )
1279 : {
1280 : const OUString sParaStyleName =
1281 : OUString::createFromAscii(
1282 0 : GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName );
1283 0 : if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() )
1284 : {
1285 0 : PropertyValue rPropVal;
1286 0 : rPropVal.Name = sParaStyleName;
1287 0 : uno::Any aVal( uno::makeAny( OUString( pTxtNode->GetTxtColl()->GetName() ) ) );
1288 0 : rPropVal.Value = aVal;
1289 0 : rPropVal.Handle = -1;
1290 0 : rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1291 :
1292 0 : aDefAttrSeq[rPropVal.Name] = rPropVal;
1293 0 : }
1294 : }
1295 :
1296 : // #i73371#
1297 : // resolve value text::WritingMode2::PAGE of property value entry WritingMode
1298 0 : if ( !bOnlyCharAttrs && GetFrm() )
1299 : {
1300 : const OUString sWritingMode =
1301 : OUString::createFromAscii(
1302 0 : GetPropName( UNO_NAME_WRITING_MODE ).pName );
1303 0 : tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode );
1304 0 : if ( aIter != aDefAttrSeq.end() )
1305 : {
1306 0 : PropertyValue rPropVal( aIter->second );
1307 0 : sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
1308 0 : if ( nVal == text::WritingMode2::PAGE )
1309 : {
1310 0 : const SwFrm* pUpperFrm( GetFrm()->GetUpper() );
1311 0 : while ( pUpperFrm )
1312 : {
1313 0 : if ( pUpperFrm->GetType() &
1314 : ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) )
1315 : {
1316 0 : if ( pUpperFrm->IsVertical() )
1317 : {
1318 0 : nVal = text::WritingMode2::TB_RL;
1319 : }
1320 0 : else if ( pUpperFrm->IsRightToLeft() )
1321 : {
1322 0 : nVal = text::WritingMode2::RL_TB;
1323 : }
1324 : else
1325 : {
1326 0 : nVal = text::WritingMode2::LR_TB;
1327 : }
1328 0 : rPropVal.Value <<= nVal;
1329 0 : aDefAttrSeq[rPropVal.Name] = rPropVal;
1330 0 : break;
1331 : }
1332 :
1333 0 : if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) )
1334 : {
1335 0 : pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm();
1336 : }
1337 : else
1338 : {
1339 0 : pUpperFrm = pUpperFrm->GetUpper();
1340 : }
1341 : }
1342 0 : }
1343 0 : }
1344 0 : }
1345 : }
1346 :
1347 0 : if ( aRequestedAttributes.getLength() == 0 )
1348 : {
1349 0 : rDefAttrSeq = aDefAttrSeq;
1350 : }
1351 : else
1352 : {
1353 0 : const OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1354 0 : const sal_Int32 nLength = aRequestedAttributes.getLength();
1355 0 : for( sal_Int32 i = 0; i < nLength; ++i )
1356 : {
1357 0 : tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] );
1358 0 : if ( aIter != aDefAttrSeq.end() )
1359 : {
1360 0 : rDefAttrSeq[ aIter->first ] = aIter->second;
1361 : }
1362 : }
1363 0 : }
1364 0 : }
1365 :
1366 0 : uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
1367 : const uno::Sequence< OUString >& aRequestedAttributes )
1368 : throw ( uno::RuntimeException )
1369 : {
1370 0 : SolarMutexGuard aGuard;
1371 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1372 :
1373 0 : tAccParaPropValMap aDefAttrSeq;
1374 0 : _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
1375 :
1376 : // #i92233#
1377 0 : static OUString sMMToPixelRatio("MMToPixelRatio");
1378 0 : bool bProvideMMToPixelRatio( false );
1379 : {
1380 0 : if ( aRequestedAttributes.getLength() == 0 )
1381 : {
1382 0 : bProvideMMToPixelRatio = true;
1383 : }
1384 : else
1385 : {
1386 : const OUString* aRequestedAttrIter =
1387 : ::std::find( ::comphelper::stl_begin( aRequestedAttributes ),
1388 : ::comphelper::stl_end( aRequestedAttributes ),
1389 0 : sMMToPixelRatio );
1390 0 : if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) )
1391 : {
1392 0 : bProvideMMToPixelRatio = true;
1393 : }
1394 : }
1395 : }
1396 :
1397 0 : uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() +
1398 0 : ( bProvideMMToPixelRatio ? 1 : 0 ) );
1399 0 : PropertyValue* pValues = aValues.getArray();
1400 0 : sal_Int32 i = 0;
1401 0 : for ( tAccParaPropValMap::const_iterator aIter = aDefAttrSeq.begin();
1402 0 : aIter != aDefAttrSeq.end();
1403 : ++aIter )
1404 : {
1405 0 : pValues[i] = aIter->second;
1406 0 : ++i;
1407 : }
1408 :
1409 : // #i92233#
1410 0 : if ( bProvideMMToPixelRatio )
1411 : {
1412 0 : PropertyValue rPropVal;
1413 0 : rPropVal.Name = sMMToPixelRatio;
1414 0 : const Size a100thMMSize( 1000, 1000 );
1415 0 : const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize );
1416 0 : const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width();
1417 0 : rPropVal.Value = uno::makeAny( fRatio );
1418 0 : rPropVal.Handle = -1;
1419 0 : rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1420 0 : pValues[ aValues.getLength() - 1 ] = rPropVal;
1421 : }
1422 :
1423 0 : return aValues;
1424 : }
1425 :
1426 0 : void SwAccessibleParagraph::_getRunAttributesImpl(
1427 : const sal_Int32 nIndex,
1428 : const uno::Sequence< OUString >& aRequestedAttributes,
1429 : tAccParaPropValMap& rRunAttrSeq )
1430 : {
1431 : // create PaM for character at position <nIndex>
1432 0 : SwPaM* pPaM( 0 );
1433 : {
1434 0 : const SwTxtNode* pTxtNode( GetTxtNode() );
1435 0 : SwPosition* pStartPos = new SwPosition( *pTxtNode );
1436 0 : pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) );
1437 0 : SwPosition* pEndPos = new SwPosition( *pTxtNode );
1438 0 : pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) );
1439 :
1440 0 : pPaM = new SwPaM( *pStartPos, *pEndPos );
1441 :
1442 0 : delete pStartPos;
1443 0 : delete pEndPos;
1444 : }
1445 :
1446 : // retrieve character attributes for the created PaM <pPaM>
1447 0 : SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(),
1448 : RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1449 0 : 0 );
1450 : // #i82637#
1451 : // From the perspective of the a11y API the character attributes, which
1452 : // are set at the automatic paragraph style of the paragraph, are treated
1453 : // as run attributes.
1454 : // SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True );
1455 : // get character attributes from automatic paragraph style and merge these into <aSet>
1456 : {
1457 0 : const SwTxtNode* pTxtNode( GetTxtNode() );
1458 0 : if ( pTxtNode->HasSwAttrSet() )
1459 : {
1460 0 : SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(),
1461 : RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1462 0 : 0 );
1463 0 : aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False );
1464 0 : aSet.Put( aAutomaticParaStyleCharAttrs );
1465 : }
1466 : }
1467 : // get character attributes at <pPaM> and merge these into <aSet>
1468 : {
1469 0 : SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(),
1470 : RES_CHRATR_BEGIN, RES_CHRATR_END -1,
1471 0 : 0 );
1472 0 : SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True);
1473 0 : aSet.Put( aCharAttrsAtPaM );
1474 : }
1475 :
1476 : // build-up sequence containing the run attributes <rRunAttrSeq>
1477 : {
1478 0 : tAccParaPropValMap aRunAttrSeq;
1479 : {
1480 0 : tAccParaPropValMap aDefAttrSeq;
1481 0 : uno::Sequence< OUString > aDummy;
1482 0 : _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true ); // #i82637#
1483 :
1484 : const SfxItemPropertyMap& rPropMap =
1485 0 : aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap();
1486 0 : PropertyEntryVector_t aPropertyEntries = rPropMap.getPropertyEntries();
1487 0 : PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin();
1488 0 : while ( aPropIt != aPropertyEntries.end() )
1489 : {
1490 0 : const SfxPoolItem* pItem( 0 );
1491 : // #i82637# - Found character attributes, whose value equals the value of
1492 : // the corresponding default character attributes, are excluded.
1493 0 : if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET )
1494 : {
1495 0 : uno::Any aVal;
1496 0 : pItem->QueryValue( aVal, aPropIt->nMemberId );
1497 :
1498 0 : PropertyValue rPropVal;
1499 0 : rPropVal.Name = aPropIt->sName;
1500 0 : rPropVal.Value = aVal;
1501 0 : rPropVal.Handle = -1;
1502 0 : rPropVal.State = PropertyState_DIRECT_VALUE;
1503 :
1504 : tAccParaPropValMap::const_iterator aDefIter =
1505 0 : aDefAttrSeq.find( rPropVal.Name );
1506 0 : if ( aDefIter == aDefAttrSeq.end() ||
1507 0 : rPropVal.Value != aDefIter->second.Value )
1508 : {
1509 0 : aRunAttrSeq[rPropVal.Name] = rPropVal;
1510 0 : }
1511 : }
1512 :
1513 0 : ++aPropIt;
1514 0 : }
1515 : }
1516 :
1517 0 : if ( aRequestedAttributes.getLength() == 0 )
1518 : {
1519 0 : rRunAttrSeq = aRunAttrSeq;
1520 : }
1521 : else
1522 : {
1523 0 : const OUString* pReqAttrs = aRequestedAttributes.getConstArray();
1524 0 : const sal_Int32 nLength = aRequestedAttributes.getLength();
1525 0 : for( sal_Int32 i = 0; i < nLength; ++i )
1526 : {
1527 0 : tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1528 0 : if ( aIter != aRunAttrSeq.end() )
1529 : {
1530 0 : rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1531 : }
1532 : }
1533 0 : }
1534 : }
1535 :
1536 0 : delete pPaM;
1537 0 : }
1538 :
1539 0 : uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
1540 : sal_Int32 nIndex,
1541 : const uno::Sequence< OUString >& aRequestedAttributes )
1542 : throw ( lang::IndexOutOfBoundsException,
1543 : uno::RuntimeException )
1544 : {
1545 0 : SolarMutexGuard aGuard;
1546 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1547 :
1548 : {
1549 0 : const OUString& rText = GetString();
1550 0 : if ( !IsValidChar( nIndex, rText.getLength() ) )
1551 : {
1552 0 : throw lang::IndexOutOfBoundsException();
1553 0 : }
1554 : }
1555 :
1556 0 : tAccParaPropValMap aRunAttrSeq;
1557 0 : _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1558 :
1559 0 : uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() );
1560 0 : PropertyValue* pValues = aValues.getArray();
1561 0 : sal_Int32 i = 0;
1562 0 : for ( tAccParaPropValMap::const_iterator aIter = aRunAttrSeq.begin();
1563 0 : aIter != aRunAttrSeq.end();
1564 : ++aIter )
1565 : {
1566 0 : pValues[i] = aIter->second;
1567 0 : ++i;
1568 : }
1569 :
1570 0 : return aValues;
1571 : }
1572 :
1573 0 : awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
1574 : sal_Int32 nIndex )
1575 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1576 : {
1577 0 : SolarMutexGuard aGuard;
1578 :
1579 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1580 :
1581 :
1582 : // #i12332# The position after the string needs special treatment.
1583 : // IsValidChar -> IsValidPosition
1584 0 : if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
1585 0 : throw lang::IndexOutOfBoundsException();
1586 :
1587 : // #i12332#
1588 0 : sal_Bool bBehindText = sal_False;
1589 0 : if ( nIndex == GetString().getLength() )
1590 0 : bBehindText = sal_True;
1591 :
1592 : // get model position & prepare GetCharRect() arguments
1593 0 : SwCrsrMoveState aMoveState;
1594 0 : aMoveState.bRealHeight = sal_True;
1595 0 : aMoveState.bRealWidth = sal_True;
1596 0 : SwSpecialPos aSpecialPos;
1597 0 : SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1598 :
1599 0 : sal_uInt16 nPos = 0;
1600 :
1601 : /** #i12332# FillSpecialPos does not accept nIndex ==
1602 : GetString().getLength(). In that case nPos is set to the
1603 : length of the string in the core. This way GetCharRect
1604 : returns the rectangle for a cursor at the end of the
1605 : paragraph. */
1606 0 : if (bBehindText)
1607 : {
1608 0 : nPos = pNode->GetTxt().getLength();
1609 : }
1610 : else
1611 0 : nPos = GetPortionData().FillSpecialPos
1612 0 : (nIndex, aSpecialPos, aMoveState.pSpecialPos );
1613 :
1614 : // call GetCharRect
1615 0 : SwRect aCoreRect;
1616 0 : SwIndex aIndex( pNode, nPos );
1617 0 : SwPosition aPosition( *pNode, aIndex );
1618 0 : GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState );
1619 :
1620 : // translate core coordinates into accessibility coordinates
1621 0 : Window *pWin = GetWindow();
1622 0 : CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1623 :
1624 0 : Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
1625 0 : SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
1626 :
1627 0 : Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
1628 0 : aScreenRect.Move( -aFrmPixPos.getX(), -aFrmPixPos.getY() );
1629 :
1630 : // convert into AWT Rectangle
1631 : return awt::Rectangle(
1632 0 : aScreenRect.Left(), aScreenRect.Top(),
1633 0 : aScreenRect.GetWidth(), aScreenRect.GetHeight() );
1634 : }
1635 :
1636 0 : sal_Int32 SwAccessibleParagraph::getCharacterCount()
1637 : throw (uno::RuntimeException)
1638 : {
1639 0 : SolarMutexGuard aGuard;
1640 :
1641 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1642 :
1643 0 : return GetString().getLength();
1644 : }
1645 :
1646 0 : sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
1647 : throw (uno::RuntimeException)
1648 : {
1649 0 : SolarMutexGuard aGuard;
1650 :
1651 :
1652 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1653 :
1654 : // construct SwPosition (where GetCrsrOfst() will put the result into)
1655 0 : SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1656 0 : SwIndex aIndex( pNode, 0);
1657 0 : SwPosition aPos( *pNode, aIndex );
1658 :
1659 : // construct Point (translate into layout coordinates)
1660 0 : Window *pWin = GetWindow();
1661 0 : CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
1662 0 : Point aPoint( rPoint.X, rPoint.Y );
1663 0 : SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root
1664 0 : Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
1665 0 : aPoint.setX(aPoint.getX() + aPixPos.getX());
1666 0 : aPoint.setY(aPoint.getY() + aPixPos.getY());
1667 0 : MapMode aMapMode = pWin->GetMapMode();
1668 0 : Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
1669 0 : if( !aLogBounds.IsInside( aCorePoint ) )
1670 : {
1671 : // #i12332# rPoint is may also be in rectangle returned by
1672 : // getCharacterBounds(getCharacterCount()
1673 :
1674 : awt::Rectangle aRectEndPos =
1675 0 : getCharacterBounds(getCharacterCount());
1676 :
1677 0 : if (rPoint.X - aRectEndPos.X >= 0 &&
1678 0 : rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
1679 0 : rPoint.Y - aRectEndPos.Y >= 0 &&
1680 0 : rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
1681 0 : return getCharacterCount();
1682 :
1683 0 : return -1;
1684 : }
1685 :
1686 : // ask core for position
1687 : OSL_ENSURE( GetFrm() != NULL, "The text frame has vanished!" );
1688 : OSL_ENSURE( GetFrm()->IsTxtFrm(), "The text frame has mutated!" );
1689 0 : const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() );
1690 0 : SwCrsrMoveState aMoveState;
1691 0 : aMoveState.bPosMatchesBounds = sal_True;
1692 0 : sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState );
1693 :
1694 0 : SwIndex aCntntIdx = aPos.nContent;
1695 0 : const xub_StrLen nIndex = aCntntIdx.GetIndex();
1696 0 : if ( nIndex > 0 )
1697 : {
1698 0 : SwRect aResultRect;
1699 0 : pFrm->GetCharRect( aResultRect, aPos );
1700 0 : bool bVert = pFrm->IsVertical();
1701 0 : bool bR2L = pFrm->IsRightToLeft();
1702 :
1703 0 : if ( (!bVert && aResultRect.Pos().getX() > aCorePoint.getX()) ||
1704 0 : ( bVert && aResultRect.Pos().getY() > aCorePoint.getY()) ||
1705 0 : ( bR2L && aResultRect.Right() < aCorePoint.getX()) )
1706 : {
1707 0 : SwIndex aIdxPrev( pNode, nIndex - 1);
1708 0 : SwPosition aPosPrev( *pNode, aIdxPrev );
1709 0 : SwRect aResultRectPrev;
1710 0 : pFrm->GetCharRect( aResultRectPrev, aPosPrev );
1711 0 : if ( (!bVert && aResultRectPrev.Pos().getX() < aCorePoint.getX() && aResultRect.Pos().getY() == aResultRectPrev.Pos().getY()) ||
1712 0 : ( bVert && aResultRectPrev.Pos().getY() < aCorePoint.getY() && aResultRect.Pos().getX() == aResultRectPrev.Pos().getX()) ||
1713 0 : ( bR2L && aResultRectPrev.Right() > aCorePoint.getX() && aResultRect.Pos().getY() == aResultRectPrev.Pos().getY()) )
1714 0 : aPos = aPosPrev;
1715 : }
1716 : }
1717 :
1718 : return bSuccess ?
1719 0 : GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() )
1720 0 : : -1L;
1721 : }
1722 :
1723 0 : OUString SwAccessibleParagraph::getSelectedText()
1724 : throw (uno::RuntimeException)
1725 : {
1726 0 : SolarMutexGuard aGuard;
1727 :
1728 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1729 :
1730 : sal_Int32 nStart, nEnd;
1731 0 : sal_Bool bSelected = GetSelection( nStart, nEnd );
1732 : return bSelected
1733 : ? GetString().copy( nStart, nEnd - nStart )
1734 0 : : OUString();
1735 : }
1736 :
1737 0 : sal_Int32 SwAccessibleParagraph::getSelectionStart()
1738 : throw (uno::RuntimeException)
1739 : {
1740 0 : SolarMutexGuard aGuard;
1741 :
1742 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1743 :
1744 : sal_Int32 nStart, nEnd;
1745 0 : GetSelection( nStart, nEnd );
1746 0 : return nStart;
1747 : }
1748 :
1749 0 : sal_Int32 SwAccessibleParagraph::getSelectionEnd()
1750 : throw (uno::RuntimeException)
1751 : {
1752 0 : SolarMutexGuard aGuard;
1753 :
1754 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1755 :
1756 : sal_Int32 nStart, nEnd;
1757 0 : GetSelection( nStart, nEnd );
1758 0 : return nEnd;
1759 : }
1760 :
1761 0 : sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1762 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1763 : {
1764 0 : SolarMutexGuard aGuard;
1765 :
1766 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1767 :
1768 : // parameter checking
1769 0 : sal_Int32 nLength = GetString().getLength();
1770 0 : if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
1771 : {
1772 0 : throw lang::IndexOutOfBoundsException();
1773 : }
1774 :
1775 0 : sal_Bool bRet = sal_False;
1776 :
1777 : // get cursor shell
1778 0 : SwCrsrShell* pCrsrShell = GetCrsrShell();
1779 0 : if( pCrsrShell != NULL )
1780 : {
1781 : // create pam for selection
1782 0 : SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
1783 0 : SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex));
1784 0 : SwPosition aStartPos( *pNode, aIndex );
1785 0 : SwPaM aPaM( aStartPos );
1786 0 : aPaM.SetMark();
1787 0 : aPaM.GetPoint()->nContent =
1788 0 : GetPortionData().GetModelPosition(nEndIndex);
1789 :
1790 : // set PaM at cursor shell
1791 0 : bRet = Select( aPaM );
1792 : }
1793 :
1794 0 : return bRet;
1795 : }
1796 :
1797 6 : OUString SwAccessibleParagraph::getText()
1798 : throw (uno::RuntimeException)
1799 : {
1800 6 : SolarMutexGuard aGuard;
1801 :
1802 6 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1803 :
1804 6 : return GetString();
1805 : }
1806 :
1807 0 : OUString SwAccessibleParagraph::getTextRange(
1808 : sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1809 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1810 : {
1811 0 : SolarMutexGuard aGuard;
1812 :
1813 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1814 :
1815 0 : OUString sText( GetString() );
1816 :
1817 0 : if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
1818 : {
1819 0 : OrderRange( nStartIndex, nEndIndex );
1820 0 : return sText.copy(nStartIndex, nEndIndex-nStartIndex );
1821 : }
1822 : else
1823 0 : throw lang::IndexOutOfBoundsException();
1824 : }
1825 :
1826 0 : /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1827 : {
1828 0 : SolarMutexGuard aGuard;
1829 :
1830 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1831 :
1832 0 : /*accessibility::*/TextSegment aResult;
1833 0 : aResult.SegmentStart = -1;
1834 0 : aResult.SegmentEnd = -1;
1835 :
1836 0 : const OUString rText = GetString();
1837 : // implement the silly specification that first position after
1838 : // text must return an empty string, rather than throwing an
1839 : // IndexOutOfBoundsException, except for LINE, where the last
1840 : // line is returned
1841 0 : if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
1842 0 : return aResult;
1843 :
1844 : // with error checking
1845 0 : i18n::Boundary aBound;
1846 0 : sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1847 :
1848 : OSL_ENSURE( aBound.startPos >= 0, "illegal boundary" );
1849 : OSL_ENSURE( aBound.startPos <= aBound.endPos, "illegal boundary" );
1850 :
1851 : // return word (if present)
1852 0 : if ( bWord )
1853 : {
1854 0 : aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1855 0 : aResult.SegmentStart = aBound.startPos;
1856 0 : aResult.SegmentEnd = aBound.endPos;
1857 : }
1858 :
1859 0 : return aResult;
1860 : }
1861 :
1862 0 : /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1863 : {
1864 0 : SolarMutexGuard aGuard;
1865 :
1866 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1867 :
1868 0 : const OUString rText = GetString();
1869 :
1870 0 : /*accessibility::*/TextSegment aResult;
1871 0 : aResult.SegmentStart = -1;
1872 0 : aResult.SegmentEnd = -1;
1873 :
1874 : // get starting pos
1875 0 : i18n::Boundary aBound;
1876 0 : if (nIndex == rText.getLength())
1877 0 : aBound.startPos = aBound.endPos = nIndex;
1878 : else
1879 : {
1880 0 : sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
1881 :
1882 0 : if ( ! bTmp )
1883 0 : aBound.startPos = aBound.endPos = nIndex;
1884 : }
1885 :
1886 : // now skip to previous word
1887 0 : sal_Bool bWord = sal_False;
1888 0 : while( !bWord )
1889 : {
1890 0 : nIndex = min( nIndex, aBound.startPos ) - 1;
1891 0 : if( nIndex >= 0 )
1892 0 : bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1893 : else
1894 0 : break; // exit if beginning of string is reached
1895 : }
1896 :
1897 0 : if ( bWord )
1898 : {
1899 0 : aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1900 0 : aResult.SegmentStart = aBound.startPos;
1901 0 : aResult.SegmentEnd = aBound.endPos;
1902 : };
1903 0 : return aResult;
1904 : }
1905 :
1906 0 : /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException)
1907 : {
1908 0 : SolarMutexGuard aGuard;
1909 :
1910 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1911 :
1912 0 : /*accessibility::*/TextSegment aResult;
1913 0 : aResult.SegmentStart = -1;
1914 0 : aResult.SegmentEnd = -1;
1915 0 : const OUString rText = GetString();
1916 :
1917 : // implement the silly specification that first position after
1918 : // text must return an empty string, rather than throwing an
1919 : // IndexOutOfBoundsException
1920 0 : if( nIndex == rText.getLength() )
1921 0 : return aResult;
1922 :
1923 :
1924 : // get first word, then skip to next word
1925 0 : i18n::Boundary aBound;
1926 0 : GetTextBoundary( aBound, rText, nIndex, nTextType );
1927 0 : sal_Bool bWord = sal_False;
1928 0 : while( !bWord )
1929 : {
1930 0 : nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
1931 0 : if( nIndex < rText.getLength() )
1932 0 : bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
1933 : else
1934 0 : break; // exit if end of string is reached
1935 : }
1936 :
1937 0 : if ( bWord )
1938 : {
1939 0 : aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
1940 0 : aResult.SegmentStart = aBound.startPos;
1941 0 : aResult.SegmentEnd = aBound.endPos;
1942 : }
1943 0 : return aResult;
1944 : }
1945 :
1946 0 : sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1947 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1948 : {
1949 0 : CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this );
1950 0 : SolarMutexGuard aGuard;
1951 :
1952 : // select and copy (through dispatch mechanism)
1953 0 : setSelection( nStartIndex, nEndIndex );
1954 0 : ExecuteAtViewShell( SID_COPY );
1955 0 : return sal_True;
1956 : }
1957 :
1958 : // XAccesibleEditableText
1959 :
1960 0 : sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1961 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1962 : {
1963 0 : CHECK_FOR_DEFUNC( XAccessibleEditableText );
1964 0 : SolarMutexGuard aGuard;
1965 :
1966 0 : if( !IsEditableState() )
1967 0 : return sal_False;
1968 :
1969 : // select and cut (through dispatch mechanism)
1970 0 : setSelection( nStartIndex, nEndIndex );
1971 0 : ExecuteAtViewShell( SID_CUT );
1972 0 : return sal_True;
1973 : }
1974 :
1975 0 : sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
1976 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1977 : {
1978 0 : CHECK_FOR_DEFUNC( XAccessibleEditableText );
1979 0 : SolarMutexGuard aGuard;
1980 :
1981 0 : if( !IsEditableState() )
1982 0 : return sal_False;
1983 :
1984 : // select and paste (through dispatch mechanism)
1985 0 : setSelection( nIndex, nIndex );
1986 0 : ExecuteAtViewShell( SID_PASTE );
1987 0 : return sal_True;
1988 : }
1989 :
1990 0 : sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
1991 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1992 : {
1993 0 : return replaceText( nStartIndex, nEndIndex, OUString() );
1994 : }
1995 :
1996 0 : sal_Bool SwAccessibleParagraph::insertText( const OUString& sText, sal_Int32 nIndex )
1997 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
1998 : {
1999 0 : return replaceText( nIndex, nIndex, sText );
2000 : }
2001 :
2002 0 : sal_Bool SwAccessibleParagraph::replaceText(
2003 : sal_Int32 nStartIndex, sal_Int32 nEndIndex,
2004 : const OUString& sReplacement )
2005 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2006 : {
2007 0 : SolarMutexGuard aGuard;
2008 :
2009 0 : CHECK_FOR_DEFUNC( XAccessibleEditableText );
2010 :
2011 0 : const OUString& rText = GetString();
2012 :
2013 0 : if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2014 : {
2015 0 : if( !IsEditableState() )
2016 0 : return sal_False;
2017 :
2018 0 : SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() );
2019 :
2020 : // translate positions
2021 : sal_uInt16 nStart, nEnd;
2022 0 : sal_Bool bSuccess = GetPortionData().GetEditableRange(
2023 0 : nStartIndex, nEndIndex, nStart, nEnd );
2024 :
2025 : // edit only if the range is editable
2026 0 : if( bSuccess )
2027 : {
2028 : // create SwPosition for nStartIndex
2029 0 : SwIndex aIndex( pNode, nStart );
2030 0 : SwPosition aStartPos( *pNode, aIndex );
2031 :
2032 : // create SwPosition for nEndIndex
2033 0 : SwPosition aEndPos( aStartPos );
2034 0 : aEndPos.nContent = nEnd;
2035 :
2036 : // now create XTextRange as helper and set string
2037 : const uno::Reference<text::XTextRange> xRange(
2038 : SwXTextRange::CreateXTextRange(
2039 0 : *pNode->GetDoc(), aStartPos, &aEndPos));
2040 0 : xRange->setString(sReplacement);
2041 :
2042 : // delete portion data
2043 0 : ClearPortionData();
2044 : }
2045 :
2046 0 : return bSuccess;
2047 : }
2048 : else
2049 0 : throw lang::IndexOutOfBoundsException();
2050 : }
2051 :
2052 : struct IndexCompare
2053 : {
2054 : const PropertyValue* pValues;
2055 0 : IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
2056 0 : bool operator() ( const sal_Int32& a, const sal_Int32& b ) const
2057 : {
2058 0 : return (pValues[a].Name < pValues[b].Name) ? true : false;
2059 : }
2060 : };
2061 :
2062 0 : sal_Bool SwAccessibleParagraph::setAttributes(
2063 : sal_Int32 nStartIndex,
2064 : sal_Int32 nEndIndex,
2065 : const uno::Sequence<PropertyValue>& rAttributeSet )
2066 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2067 : {
2068 0 : SolarMutexGuard aGuard;
2069 0 : CHECK_FOR_DEFUNC( XAccessibleEditableText );
2070 :
2071 0 : const OUString& rText = GetString();
2072 :
2073 0 : if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2074 0 : throw lang::IndexOutOfBoundsException();
2075 :
2076 0 : if( !IsEditableState() )
2077 0 : return sal_False;
2078 :
2079 : // create a (dummy) text portion for the sole purpose of calling
2080 : // setPropertyValue on it
2081 : uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
2082 0 : nEndIndex );
2083 :
2084 : // build sorted index array
2085 0 : sal_Int32 nLength = rAttributeSet.getLength();
2086 0 : const PropertyValue* pPairs = rAttributeSet.getConstArray();
2087 0 : sal_Int32* pIndices = new sal_Int32[nLength];
2088 : sal_Int32 i;
2089 0 : for( i = 0; i < nLength; i++ )
2090 0 : pIndices[i] = i;
2091 0 : sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
2092 :
2093 : // create sorted sequences accoring to index array
2094 0 : uno::Sequence< OUString > aNames( nLength );
2095 0 : OUString* pNames = aNames.getArray();
2096 0 : uno::Sequence< uno::Any > aValues( nLength );
2097 0 : uno::Any* pValues = aValues.getArray();
2098 0 : for( i = 0; i < nLength; i++ )
2099 : {
2100 0 : const PropertyValue& rVal = pPairs[pIndices[i]];
2101 0 : pNames[i] = rVal.Name;
2102 0 : pValues[i] = rVal.Value;
2103 : }
2104 0 : delete[] pIndices;
2105 :
2106 : // now set the values
2107 0 : sal_Bool bRet = sal_True;
2108 : try
2109 : {
2110 0 : xPortion->setPropertyValues( aNames, aValues );
2111 : }
2112 0 : catch (const UnknownPropertyException&)
2113 : {
2114 : // error handling through return code!
2115 0 : bRet = sal_False;
2116 : }
2117 :
2118 0 : return bRet;
2119 : }
2120 :
2121 0 : sal_Bool SwAccessibleParagraph::setText( const OUString& sText )
2122 : throw (uno::RuntimeException)
2123 : {
2124 0 : return replaceText(0, GetString().getLength(), sText);
2125 : }
2126 :
2127 : // XAccessibleSelection
2128 :
2129 2 : void SwAccessibleParagraph::selectAccessibleChild(
2130 : sal_Int32 nChildIndex )
2131 : throw ( lang::IndexOutOfBoundsException,
2132 : uno::RuntimeException )
2133 : {
2134 2 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2135 :
2136 2 : aSelectionHelper.selectAccessibleChild(nChildIndex);
2137 0 : }
2138 :
2139 2 : sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
2140 : sal_Int32 nChildIndex )
2141 : throw ( lang::IndexOutOfBoundsException,
2142 : uno::RuntimeException )
2143 : {
2144 2 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2145 :
2146 2 : return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
2147 : }
2148 :
2149 2 : void SwAccessibleParagraph::clearAccessibleSelection( )
2150 : throw ( uno::RuntimeException )
2151 : {
2152 2 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2153 :
2154 2 : aSelectionHelper.clearAccessibleSelection();
2155 2 : }
2156 :
2157 3 : void SwAccessibleParagraph::selectAllAccessibleChildren( )
2158 : throw ( uno::RuntimeException )
2159 : {
2160 3 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2161 :
2162 3 : aSelectionHelper.selectAllAccessibleChildren();
2163 3 : }
2164 :
2165 5 : sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount( )
2166 : throw ( uno::RuntimeException )
2167 : {
2168 5 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2169 :
2170 5 : return aSelectionHelper.getSelectedAccessibleChildCount();
2171 : }
2172 :
2173 2 : uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
2174 : sal_Int32 nSelectedChildIndex )
2175 : throw ( lang::IndexOutOfBoundsException,
2176 : uno::RuntimeException)
2177 : {
2178 2 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2179 :
2180 2 : return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
2181 : }
2182 :
2183 : // index has to be treated as global child index.
2184 2 : void SwAccessibleParagraph::deselectAccessibleChild(
2185 : sal_Int32 nChildIndex )
2186 : throw ( lang::IndexOutOfBoundsException,
2187 : uno::RuntimeException )
2188 : {
2189 2 : CHECK_FOR_DEFUNC( XAccessibleSelection );
2190 :
2191 2 : aSelectionHelper.deselectAccessibleChild( nChildIndex );
2192 0 : }
2193 :
2194 : // XAccessibleHypertext
2195 :
2196 : class SwHyperlinkIter_Impl
2197 : {
2198 : const SwpHints *pHints;
2199 : xub_StrLen nStt;
2200 : xub_StrLen nEnd;
2201 : sal_uInt16 nPos;
2202 :
2203 : public:
2204 : SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm );
2205 : const SwTxtAttr *next();
2206 0 : sal_uInt16 getCurrHintPos() const { return nPos-1; }
2207 :
2208 0 : xub_StrLen startIdx() const { return nStt; }
2209 0 : xub_StrLen endIdx() const { return nEnd; }
2210 : };
2211 :
2212 0 : SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) :
2213 0 : pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ),
2214 0 : nStt( pTxtFrm->GetOfst() ),
2215 0 : nPos( 0 )
2216 : {
2217 0 : const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow();
2218 0 : nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len();
2219 0 : }
2220 :
2221 0 : const SwTxtAttr *SwHyperlinkIter_Impl::next()
2222 : {
2223 0 : const SwTxtAttr *pAttr = 0;
2224 0 : if( pHints )
2225 : {
2226 0 : while( !pAttr && nPos < pHints->Count() )
2227 : {
2228 0 : const SwTxtAttr *pHt = (*pHints)[nPos];
2229 0 : if( RES_TXTATR_INETFMT == pHt->Which() )
2230 : {
2231 0 : xub_StrLen nHtStt = *pHt->GetStart();
2232 0 : xub_StrLen nHtEnd = *pHt->GetAnyEnd();
2233 0 : if( nHtEnd > nHtStt &&
2234 0 : ( (nHtStt >= nStt && nHtStt < nEnd) ||
2235 0 : (nHtEnd > nStt && nHtEnd <= nEnd) ) )
2236 : {
2237 0 : pAttr = pHt;
2238 : }
2239 : }
2240 0 : ++nPos;
2241 : }
2242 : }
2243 :
2244 0 : return pAttr;
2245 : };
2246 :
2247 0 : sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
2248 : throw (uno::RuntimeException)
2249 : {
2250 0 : SolarMutexGuard aGuard;
2251 :
2252 0 : CHECK_FOR_DEFUNC( XAccessibleHypertext );
2253 :
2254 0 : sal_Int32 nCount = 0;
2255 : // #i77108# - provide hyperlinks also in editable documents.
2256 :
2257 0 : const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2258 0 : SwHyperlinkIter_Impl aIter( pTxtFrm );
2259 0 : while( aIter.next() )
2260 0 : nCount++;
2261 :
2262 0 : return nCount;
2263 : }
2264 :
2265 : uno::Reference< XAccessibleHyperlink > SAL_CALL
2266 0 : SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
2267 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2268 : {
2269 0 : SolarMutexGuard aGuard;
2270 0 : CHECK_FOR_DEFUNC( XAccessibleHypertext );
2271 :
2272 0 : uno::Reference< XAccessibleHyperlink > xRet;
2273 :
2274 : // #i77108#
2275 : {
2276 0 : const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2277 0 : SwHyperlinkIter_Impl aHIter( pTxtFrm );
2278 0 : while( nLinkIndex-- )
2279 0 : aHIter.next();
2280 :
2281 0 : const SwTxtAttr *pHt = aHIter.next();
2282 0 : if( pHt )
2283 : {
2284 0 : if( !pHyperTextData )
2285 0 : pHyperTextData = new SwAccessibleHyperTextData;
2286 : SwAccessibleHyperTextData::iterator aIter =
2287 0 : pHyperTextData ->find( pHt );
2288 0 : if( aIter != pHyperTextData->end() )
2289 : {
2290 0 : xRet = (*aIter).second;
2291 : }
2292 0 : if( !xRet.is() )
2293 : {
2294 0 : sal_Int32 nHStt= GetPortionData().GetAccessiblePosition(
2295 0 : max( aHIter.startIdx(), *pHt->GetStart() ) );
2296 0 : sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition(
2297 0 : min( aHIter.endIdx(), *pHt->GetAnyEnd() ) );
2298 0 : xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(),
2299 0 : this, nHStt, nHEnd );
2300 0 : if( aIter != pHyperTextData->end() )
2301 : {
2302 0 : (*aIter).second = xRet;
2303 : }
2304 : else
2305 : {
2306 0 : SwAccessibleHyperTextData::value_type aEntry( pHt, xRet );
2307 0 : pHyperTextData->insert( aEntry );
2308 : }
2309 : }
2310 : }
2311 : }
2312 :
2313 0 : if( !xRet.is() )
2314 0 : throw lang::IndexOutOfBoundsException();
2315 :
2316 0 : return xRet;
2317 : }
2318 :
2319 0 : sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
2320 : throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
2321 : {
2322 0 : SolarMutexGuard aGuard;
2323 0 : CHECK_FOR_DEFUNC( XAccessibleHypertext );
2324 :
2325 : // parameter checking
2326 0 : sal_Int32 nLength = GetString().getLength();
2327 0 : if ( ! IsValidPosition( nCharIndex, nLength ) )
2328 : {
2329 0 : throw lang::IndexOutOfBoundsException();
2330 : }
2331 :
2332 0 : sal_Int32 nRet = -1;
2333 : // #i77108#
2334 : {
2335 0 : const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() );
2336 0 : SwHyperlinkIter_Impl aHIter( pTxtFrm );
2337 :
2338 0 : xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex );
2339 0 : sal_Int32 nPos = 0;
2340 0 : const SwTxtAttr *pHt = aHIter.next();
2341 0 : while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) )
2342 : {
2343 0 : pHt = aHIter.next();
2344 0 : nPos++;
2345 : }
2346 :
2347 0 : if( pHt )
2348 0 : nRet = nPos;
2349 :
2350 : }
2351 :
2352 0 : return nRet;
2353 : }
2354 :
2355 : // #i71360#, #i108125# - adjustments for change tracking text markup
2356 0 : sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
2357 : throw (lang::IllegalArgumentException,
2358 : uno::RuntimeException)
2359 : {
2360 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
2361 0 : std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2362 : SAL_WNODEPRECATED_DECLARATIONS_POP
2363 0 : switch ( nTextMarkupType )
2364 : {
2365 : case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2366 : case text::TextMarkupType::TRACK_CHANGE_DELETION:
2367 : case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2368 : {
2369 : pTextMarkupHelper.reset( new SwTextMarkupHelper(
2370 : GetPortionData(),
2371 0 : *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2372 : }
2373 0 : break;
2374 : default:
2375 : {
2376 0 : pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2377 : }
2378 : }
2379 :
2380 0 : return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType );
2381 : }
2382 :
2383 : /*accessibility::*/TextSegment SAL_CALL
2384 0 : SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
2385 : sal_Int32 nTextMarkupType )
2386 : throw (lang::IndexOutOfBoundsException,
2387 : lang::IllegalArgumentException,
2388 : uno::RuntimeException)
2389 : {
2390 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
2391 0 : std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2392 : SAL_WNODEPRECATED_DECLARATIONS_POP
2393 0 : switch ( nTextMarkupType )
2394 : {
2395 : case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2396 : case text::TextMarkupType::TRACK_CHANGE_DELETION:
2397 : case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2398 : {
2399 : pTextMarkupHelper.reset( new SwTextMarkupHelper(
2400 : GetPortionData(),
2401 0 : *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2402 : }
2403 0 : break;
2404 : default:
2405 : {
2406 0 : pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2407 : }
2408 : }
2409 :
2410 0 : return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
2411 : }
2412 :
2413 : uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
2414 0 : SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
2415 : sal_Int32 nTextMarkupType )
2416 : throw (lang::IndexOutOfBoundsException,
2417 : lang::IllegalArgumentException,
2418 : uno::RuntimeException)
2419 : {
2420 : // parameter checking
2421 0 : const sal_Int32 nLength = GetString().getLength();
2422 0 : if ( ! IsValidPosition( nCharIndex, nLength ) )
2423 : {
2424 0 : throw lang::IndexOutOfBoundsException();
2425 : }
2426 :
2427 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
2428 0 : std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2429 : SAL_WNODEPRECATED_DECLARATIONS_POP
2430 0 : switch ( nTextMarkupType )
2431 : {
2432 : case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2433 : case text::TextMarkupType::TRACK_CHANGE_DELETION:
2434 : case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2435 : {
2436 : pTextMarkupHelper.reset( new SwTextMarkupHelper(
2437 : GetPortionData(),
2438 0 : *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2439 : }
2440 0 : break;
2441 : default:
2442 : {
2443 0 : pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) );
2444 : }
2445 : }
2446 :
2447 0 : return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
2448 : }
2449 :
2450 : // #i89175#
2451 0 : sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
2452 : throw (lang::IndexOutOfBoundsException,
2453 : uno::RuntimeException)
2454 : {
2455 : // parameter checking
2456 0 : const sal_Int32 nLength = GetString().getLength();
2457 0 : if ( ! IsValidPosition( nIndex, nLength ) )
2458 : {
2459 0 : throw lang::IndexOutOfBoundsException();
2460 : }
2461 :
2462 0 : const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
2463 0 : return nLineNo;
2464 : }
2465 :
2466 : /*accessibility::*/TextSegment SAL_CALL
2467 0 : SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
2468 : throw (lang::IndexOutOfBoundsException,
2469 : uno::RuntimeException)
2470 : {
2471 : // parameter checking
2472 0 : if ( nLineNo < 0 ||
2473 0 : nLineNo >= GetPortionData().GetLineCount() )
2474 : {
2475 0 : throw lang::IndexOutOfBoundsException();
2476 : }
2477 :
2478 0 : i18n::Boundary aLineBound;
2479 0 : GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2480 :
2481 0 : /*accessibility::*/TextSegment aTextAtLine;
2482 0 : const OUString rText = GetString();
2483 0 : aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
2484 0 : aLineBound.endPos - aLineBound.startPos );
2485 0 : aTextAtLine.SegmentStart = aLineBound.startPos;
2486 0 : aTextAtLine.SegmentEnd = aLineBound.endPos;
2487 :
2488 0 : return aTextAtLine;
2489 : }
2490 :
2491 0 : /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
2492 : throw (uno::RuntimeException)
2493 : {
2494 0 : const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
2495 :
2496 0 : if ( nLineNoOfCaret >= 0 &&
2497 0 : nLineNoOfCaret < GetPortionData().GetLineCount() )
2498 : {
2499 0 : return getTextAtLineNumber( nLineNoOfCaret );
2500 : }
2501 :
2502 0 : return /*accessibility::*/TextSegment();
2503 : }
2504 :
2505 0 : sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
2506 : throw (uno::RuntimeException)
2507 : {
2508 0 : const sal_Int32 nCaretPos = getCaretPosition();
2509 0 : const sal_Int32 nLength = GetString().getLength();
2510 0 : if ( !IsValidPosition( nCaretPos, nLength ) )
2511 : {
2512 0 : return -1;
2513 : }
2514 :
2515 0 : sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
2516 :
2517 : // special handling for cursor positioned at end of text line via End key
2518 0 : if ( nCaretPos != 0 )
2519 : {
2520 0 : i18n::Boundary aLineBound;
2521 0 : GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
2522 0 : if ( nCaretPos == aLineBound.startPos )
2523 : {
2524 0 : SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell();
2525 0 : if ( pCrsrShell != 0 )
2526 : {
2527 0 : const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
2528 :
2529 0 : const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect();
2530 : // translate core coordinates into accessibility coordinates
2531 0 : Window *pWin = GetWindow();
2532 0 : CHECK_FOR_WINDOW( XAccessibleComponent, pWin );
2533 :
2534 0 : Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
2535 :
2536 0 : SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2537 0 : Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() );
2538 0 : aScreenRect.Move( -aFrmPixPos.getX(), -aFrmPixPos.getY() );
2539 :
2540 : // convert into AWT Rectangle
2541 0 : const awt::Rectangle aCursorRect( aScreenRect.Left(),
2542 0 : aScreenRect.Top(),
2543 0 : aScreenRect.GetWidth(),
2544 0 : aScreenRect.GetHeight() );
2545 :
2546 0 : if ( aCharRect.X != aCursorRect.X ||
2547 0 : aCharRect.Y != aCursorRect.Y )
2548 : {
2549 0 : --nLineNo;
2550 : }
2551 : }
2552 : }
2553 : }
2554 :
2555 0 : return nLineNo;
2556 : }
2557 :
2558 : // #i108125#
2559 87 : void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2560 : {
2561 87 : mpParaChangeTrackInfo->reset();
2562 :
2563 87 : CheckRegistration( pOld, pNew );
2564 186 : }
2565 :
2566 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|