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