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 : //------------------------------------------------------------------------
22 : //
23 : // Global header
24 : //
25 : //------------------------------------------------------------------------
26 :
27 : #include <limits.h>
28 : #include <vector>
29 : #include <algorithm>
30 : #include <boost/ref.hpp>
31 : #include <osl/mutex.hxx>
32 : #include <vcl/window.hxx>
33 : #include <vcl/svapp.hxx>
34 : #include <comphelper/sequenceasvector.hxx>
35 : #include <com/sun/star/uno/Any.hxx>
36 : #include <com/sun/star/uno/Reference.hxx>
37 : #include <com/sun/star/awt/Point.hpp>
38 : #include <com/sun/star/awt/Rectangle.hpp>
39 : #include <com/sun/star/accessibility/AccessibleTextType.hpp>
40 :
41 : //------------------------------------------------------------------------
42 : //
43 : // Project-local header
44 : //
45 : //------------------------------------------------------------------------
46 :
47 : #include <editeng/editdata.hxx>
48 : #include <editeng/unopracc.hxx>
49 : #include "editeng/unoedprx.hxx"
50 : #include <editeng/AccessibleStaticTextBase.hxx>
51 : #include "editeng/AccessibleEditableTextPara.hxx"
52 :
53 :
54 : using namespace ::com::sun::star;
55 : using namespace ::com::sun::star::accessibility;
56 :
57 : /* TODO:
58 : =====
59 :
60 : - separate adapter functionality from AccessibleStaticText class
61 :
62 : - refactor common loops into templates, using mem_fun
63 :
64 : */
65 :
66 : namespace accessibility
67 : {
68 : typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector;
69 :
70 : class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool >
71 : {
72 : public:
73 0 : PropertyValueEqualFunctor()
74 0 : {}
75 0 : bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const
76 : {
77 0 : return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value );
78 : }
79 : };
80 :
81 : //------------------------------------------------------------------------
82 : //
83 : // Static Helper
84 : //
85 : //------------------------------------------------------------------------
86 0 : ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
87 : sal_Int32 nEndPara, sal_Int32 nEndIndex )
88 : {
89 : DBG_ASSERT(nStartPara >= 0 && nStartPara <= SAL_MAX_INT32 &&
90 : nStartIndex >= 0 && nStartIndex <= USHRT_MAX &&
91 : nEndPara >= 0 && nEndPara <= SAL_MAX_INT32 &&
92 : nEndIndex >= 0 && nEndIndex <= USHRT_MAX ,
93 : "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
94 :
95 : return ESelection( nStartPara, static_cast< sal_uInt16 >(nStartIndex),
96 0 : nEndPara, static_cast< sal_uInt16 >(nEndIndex) );
97 : }
98 :
99 : //------------------------------------------------------------------------
100 : //
101 : // AccessibleStaticTextBase_Impl declaration
102 : //
103 : //------------------------------------------------------------------------
104 :
105 : DBG_NAME( AccessibleStaticTextBase_Impl );
106 :
107 : /** AccessibleStaticTextBase_Impl
108 :
109 : This class implements the AccessibleStaticTextBase
110 : functionality, mainly by forwarding the calls to an aggregated
111 : AccessibleEditableTextPara. As this is a therefore non-trivial
112 : adapter, factoring out the common functionality from
113 : AccessibleEditableTextPara might be a profitable future task.
114 : */
115 : class AccessibleStaticTextBase_Impl
116 : {
117 :
118 : public:
119 :
120 : // receive pointer to our frontend class and view window
121 : AccessibleStaticTextBase_Impl();
122 : ~AccessibleStaticTextBase_Impl();
123 :
124 0 : SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException))
125 : {
126 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
127 :
128 0 : return maEditSource;
129 : }
130 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
131 : void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
132 : SAL_WNODEPRECATED_DECLARATIONS_POP
133 :
134 11 : void SetEventSource( const uno::Reference< XAccessible >& rInterface )
135 : {
136 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
137 :
138 11 : mxThis = rInterface;
139 11 : }
140 0 : uno::Reference< XAccessible > GetEventSource() const
141 : {
142 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
143 :
144 0 : return mxThis;
145 : }
146 :
147 : void SetOffset( const Point& );
148 0 : Point GetOffset() const
149 : {
150 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
151 :
152 0 : ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
153 0 : return aPoint;
154 : }
155 :
156 : void UpdateChildren();
157 : void Dispose();
158 :
159 : #ifdef DBG_UTIL
160 : void CheckInvariants() const;
161 : #endif
162 :
163 : AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const;
164 : sal_Int32 GetParagraphCount() const;
165 :
166 0 : EPosition Index2Internal( sal_Int32 nFlatIndex ) const
167 : {
168 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
169 :
170 0 : return ImpCalcInternal( nFlatIndex, false );
171 : }
172 :
173 0 : EPosition Range2Internal( sal_Int32 nFlatIndex ) const
174 : {
175 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
176 :
177 0 : return ImpCalcInternal( nFlatIndex, true );
178 : }
179 :
180 : sal_Int32 Internal2Index( EPosition nEEIndex ) const;
181 :
182 : void CorrectTextSegment( TextSegment& aTextSegment,
183 : int nPara ) const;
184 :
185 : sal_Bool SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
186 : sal_Int32 nEndPara, sal_Int32 nEndIndex );
187 : sal_Bool CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
188 : sal_Int32 nEndPara, sal_Int32 nEndIndex );
189 :
190 : Rectangle GetParagraphBoundingBox() const;
191 :
192 : private:
193 :
194 : EPosition ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const;
195 :
196 : // our frontend class (the one implementing the actual
197 : // interface). That's not necessarily the one containing the impl
198 : // pointer
199 : uno::Reference< XAccessible > mxThis;
200 :
201 : // implements our functionality, we're just an adapter (guarded by solar mutex)
202 : mutable AccessibleEditableTextPara* mpTextParagraph;
203 :
204 : uno::Reference< XAccessible > mxParagraph;
205 :
206 : // a wrapper for the text forwarders (guarded by solar mutex)
207 : mutable SvxEditSourceAdapter maEditSource;
208 :
209 : // guard for maOffset
210 : mutable ::osl::Mutex maMutex;
211 :
212 : /// our current offset to the containing shape/cell (guarded by maMutex)
213 : Point maOffset;
214 :
215 : };
216 :
217 : //------------------------------------------------------------------------
218 : //
219 : // AccessibleStaticTextBase_Impl implementation
220 : //
221 : //------------------------------------------------------------------------
222 :
223 5 : AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
224 : mxThis( NULL ),
225 5 : mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
226 : mxParagraph( mpTextParagraph ),
227 : maEditSource(),
228 : maMutex(),
229 10 : maOffset(0,0)
230 : {
231 : DBG_CTOR( AccessibleStaticTextBase_Impl, NULL );
232 :
233 : // TODO: this is still somewhat of a hack, all the more since
234 : // now the maTextParagraph has an empty parent reference set
235 5 : }
236 :
237 5 : AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
238 : {
239 : DBG_DTOR( AccessibleStaticTextBase_Impl, NULL );
240 5 : }
241 :
242 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
243 5 : void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
244 : {
245 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
246 :
247 5 : maEditSource.SetEditSource( pEditSource );
248 5 : if( mpTextParagraph )
249 5 : mpTextParagraph->SetEditSource( &maEditSource );
250 5 : }
251 : SAL_WNODEPRECATED_DECLARATIONS_POP
252 :
253 10 : void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint )
254 : {
255 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
256 :
257 : // guard against non-atomic access to maOffset data structure
258 : {
259 10 : ::osl::MutexGuard aGuard( maMutex );
260 10 : maOffset = rPoint;
261 : }
262 :
263 10 : if( mpTextParagraph )
264 10 : mpTextParagraph->SetEEOffset( rPoint );
265 :
266 : // in all cases, check visibility afterwards.
267 10 : UpdateChildren();
268 10 : }
269 :
270 10 : void AccessibleStaticTextBase_Impl::UpdateChildren()
271 : {
272 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
273 :
274 : // currently no children
275 10 : }
276 :
277 5 : void AccessibleStaticTextBase_Impl::Dispose()
278 : {
279 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
280 :
281 : // we're the owner of the paragraph, so destroy it, too
282 5 : if( mpTextParagraph )
283 5 : mpTextParagraph->Dispose();
284 :
285 : // drop references
286 5 : mxParagraph = NULL;
287 5 : mxThis = NULL;
288 5 : mpTextParagraph = NULL;
289 5 : }
290 :
291 : #ifdef DBG_UTIL
292 : void AccessibleStaticTextBase_Impl::CheckInvariants() const
293 : {
294 : // TODO
295 : }
296 : #endif
297 :
298 0 : AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const
299 : {
300 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
301 :
302 0 : if( !mpTextParagraph )
303 0 : throw lang::DisposedException ("object has been already disposed", mxThis );
304 :
305 : // TODO: Have a different method on AccessibleEditableTextPara
306 : // that does not care about state changes
307 0 : mpTextParagraph->SetParagraphIndex( nPara );
308 :
309 0 : return *mpTextParagraph;
310 : }
311 :
312 0 : sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const
313 : {
314 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
315 :
316 0 : if( !mpTextParagraph )
317 0 : return 0;
318 : else
319 0 : return mpTextParagraph->GetTextForwarder().GetParagraphCount();
320 : }
321 :
322 0 : sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
323 : {
324 : // XXX checks for overflow and returns maximum if so
325 0 : sal_Int32 aRes(0);
326 0 : for(sal_Int32 i=0; i<nEEIndex.nPara; ++i)
327 : {
328 0 : sal_Int32 nCount = GetParagraph(i).getCharacterCount();
329 0 : if (SAL_MAX_INT32 - aRes > nCount)
330 0 : return SAL_MAX_INT32;
331 0 : aRes += nCount;
332 : }
333 :
334 0 : if (SAL_MAX_INT32 - aRes > nEEIndex.nIndex)
335 0 : return SAL_MAX_INT32;
336 0 : return aRes + nEEIndex.nIndex;
337 : }
338 :
339 0 : void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment,
340 : int nPara ) const
341 : {
342 : // Keep 'invalid' values at the TextSegment
343 0 : if( aTextSegment.SegmentStart != -1 &&
344 0 : aTextSegment.SegmentEnd != -1 )
345 : {
346 : // #112814# Correct TextSegment by paragraph offset
347 0 : sal_Int32 nOffset(0);
348 : int i;
349 0 : for(i=0; i<nPara; ++i)
350 0 : nOffset += GetParagraph(i).getCharacterCount();
351 :
352 0 : aTextSegment.SegmentStart += nOffset;
353 0 : aTextSegment.SegmentEnd += nOffset;
354 : }
355 0 : }
356 :
357 0 : EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const
358 : {
359 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
360 :
361 0 : if( nFlatIndex < 0 )
362 : throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
363 0 : mxThis);
364 : // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
365 :
366 : sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount;
367 0 : for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara )
368 : {
369 0 : nCurrCount = GetParagraph( nCurrPara ).getCharacterCount();
370 0 : nCurrIndex += nCurrCount;
371 :
372 0 : if( nCurrIndex > nFlatIndex )
373 : {
374 : // check overflow
375 : DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= SAL_MAX_INT32 &&
376 : nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
377 : "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
378 :
379 0 : return EPosition( nCurrPara, static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
380 : }
381 : }
382 :
383 : // #102170# Allow one-past the end for ranges
384 0 : if( bExclusive && nCurrIndex == nFlatIndex )
385 : {
386 : // check overflow
387 : DBG_ASSERT(nCurrPara > 0 && nCurrPara <= SAL_MAX_INT32 &&
388 : nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
389 : "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
390 :
391 0 : return EPosition( nCurrPara-1, static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
392 : }
393 :
394 : // not found? Out of bounds
395 : throw lang::IndexOutOfBoundsException("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds",
396 0 : mxThis);
397 : }
398 :
399 0 : sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
400 : sal_Int32 nEndPara, sal_Int32 nEndIndex )
401 : {
402 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
403 :
404 0 : if( !mpTextParagraph )
405 0 : return sal_False;
406 :
407 : try
408 : {
409 0 : SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
410 0 : return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
411 : }
412 0 : catch( const uno::RuntimeException& )
413 : {
414 0 : return sal_False;
415 : }
416 : }
417 :
418 0 : sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
419 : sal_Int32 nEndPara, sal_Int32 nEndIndex )
420 : {
421 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
422 :
423 0 : if( !mpTextParagraph )
424 0 : return sal_False;
425 :
426 : try
427 : {
428 0 : SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
429 0 : mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
430 : sal_Bool aRetVal;
431 :
432 : // save current selection
433 0 : ESelection aOldSelection;
434 :
435 0 : rCacheVF.GetSelection( aOldSelection );
436 0 : rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
437 0 : aRetVal = rCacheVF.Copy();
438 0 : rCacheVF.SetSelection( aOldSelection ); // restore
439 :
440 0 : return aRetVal;
441 : }
442 0 : catch( const uno::RuntimeException& )
443 : {
444 0 : return sal_False;
445 : }
446 : }
447 :
448 0 : Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
449 : {
450 0 : Rectangle aRect;
451 0 : if( mpTextParagraph )
452 : {
453 0 : awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
454 0 : aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
455 : }
456 : else
457 : {
458 0 : aRect.SetEmpty();
459 : }
460 0 : return aRect;
461 : }
462 :
463 : //------------------------------------------------------------------------
464 : //
465 : // AccessibleStaticTextBase implementation
466 : //
467 : //------------------------------------------------------------------------
468 :
469 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
470 5 : AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) :
471 5 : mpImpl( new AccessibleStaticTextBase_Impl() )
472 : {
473 5 : SolarMutexGuard aGuard;
474 :
475 5 : SetEditSource( pEditSource );
476 5 : }
477 : SAL_WNODEPRECATED_DECLARATIONS_POP
478 :
479 5 : AccessibleStaticTextBase::~AccessibleStaticTextBase()
480 : {
481 5 : }
482 :
483 0 : const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException))
484 : {
485 : #ifdef DBG_UTIL
486 : mpImpl->CheckInvariants();
487 :
488 : const SvxEditSource& aEditSource = mpImpl->GetEditSource();
489 :
490 : mpImpl->CheckInvariants();
491 :
492 : return aEditSource;
493 : #else
494 0 : return mpImpl->GetEditSource();
495 : #endif
496 : }
497 :
498 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
499 5 : void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException))
500 : {
501 : #ifdef DBG_UTIL
502 : // precondition: solar mutex locked
503 : DBG_TESTSOLARMUTEX();
504 :
505 : mpImpl->CheckInvariants();
506 :
507 : mpImpl->SetEditSource( pEditSource );
508 :
509 : mpImpl->CheckInvariants();
510 : #else
511 5 : mpImpl->SetEditSource( pEditSource );
512 : #endif
513 5 : }
514 : SAL_WNODEPRECATED_DECLARATIONS_POP
515 :
516 11 : void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
517 : {
518 : #ifdef DBG_UTIL
519 : mpImpl->CheckInvariants();
520 : #endif
521 :
522 11 : mpImpl->SetEventSource( rInterface );
523 :
524 : #ifdef DBG_UTIL
525 : mpImpl->CheckInvariants();
526 : #endif
527 11 : }
528 :
529 0 : uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const
530 : {
531 : #ifdef DBG_UTIL
532 : mpImpl->CheckInvariants();
533 :
534 : uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
535 :
536 : mpImpl->CheckInvariants();
537 :
538 : return xRet;
539 : #else
540 0 : return mpImpl->GetEventSource();
541 : #endif
542 : }
543 :
544 10 : void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
545 : {
546 : #ifdef DBG_UTIL
547 : // precondition: solar mutex locked
548 : DBG_TESTSOLARMUTEX();
549 :
550 : mpImpl->CheckInvariants();
551 :
552 : mpImpl->SetOffset( rPoint );
553 :
554 : mpImpl->CheckInvariants();
555 : #else
556 10 : mpImpl->SetOffset( rPoint );
557 : #endif
558 10 : }
559 :
560 0 : Point AccessibleStaticTextBase::GetOffset() const
561 : {
562 : #ifdef DBG_UTIL
563 : mpImpl->CheckInvariants();
564 :
565 : Point aPoint( mpImpl->GetOffset() );
566 :
567 : mpImpl->CheckInvariants();
568 :
569 : return aPoint;
570 : #else
571 0 : return mpImpl->GetOffset();
572 : #endif
573 : }
574 :
575 0 : void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
576 : {
577 : #ifdef DBG_UTIL
578 : // precondition: solar mutex locked
579 : DBG_TESTSOLARMUTEX();
580 :
581 : mpImpl->CheckInvariants();
582 :
583 : mpImpl->UpdateChildren();
584 :
585 : mpImpl->CheckInvariants();
586 : #else
587 0 : mpImpl->UpdateChildren();
588 : #endif
589 0 : }
590 :
591 5 : void AccessibleStaticTextBase::Dispose()
592 : {
593 : #ifdef DBG_UTIL
594 : mpImpl->CheckInvariants();
595 : #endif
596 :
597 5 : mpImpl->Dispose();
598 :
599 : #ifdef DBG_UTIL
600 : mpImpl->CheckInvariants();
601 : #endif
602 5 : }
603 :
604 : // XAccessibleContext
605 8 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException)
606 : {
607 : // no children at all
608 8 : return 0;
609 : }
610 :
611 0 : uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
612 : {
613 : // no children at all
614 0 : return uno::Reference< XAccessible >();
615 : }
616 :
617 0 : uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException)
618 : {
619 : // no children at all
620 0 : return uno::Reference< XAccessible >();
621 : }
622 :
623 : // XAccessibleText
624 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException)
625 : {
626 0 : SolarMutexGuard aGuard;
627 :
628 : sal_Int32 i, nPos, nParas;
629 0 : for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
630 : {
631 0 : if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 )
632 0 : return nPos;
633 : }
634 :
635 0 : return nPos;
636 : }
637 :
638 0 : sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
639 : {
640 0 : return setSelection(nIndex, nIndex);
641 : }
642 :
643 0 : sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
644 : {
645 0 : SolarMutexGuard aGuard;
646 :
647 0 : EPosition aPos( mpImpl->Index2Internal(nIndex) );
648 :
649 0 : return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex );
650 : }
651 :
652 0 : uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< OUString >& aRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
653 : {
654 0 : SolarMutexGuard aGuard;
655 :
656 0 : EPosition aPos( mpImpl->Index2Internal(nIndex) );
657 :
658 0 : return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes );
659 : }
660 :
661 0 : awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
662 : {
663 0 : SolarMutexGuard aGuard;
664 :
665 : // #108900# Allow ranges for nIndex, as one-past-the-end
666 : // values are now legal, too.
667 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
668 :
669 : // #i70916# Text in spread sheet cells return the wrong extents
670 0 : AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
671 0 : awt::Rectangle aParaBounds( rPara.getBounds() );
672 0 : awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) );
673 0 : aBounds.X += aParaBounds.X;
674 0 : aBounds.Y += aParaBounds.Y;
675 :
676 0 : return aBounds;
677 : }
678 :
679 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException)
680 : {
681 0 : SolarMutexGuard aGuard;
682 :
683 : sal_Int32 i, nCount, nParas;
684 0 : for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
685 0 : nCount += mpImpl->GetParagraph(i).getCharacterCount();
686 :
687 0 : return nCount;
688 : }
689 :
690 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
691 : {
692 0 : SolarMutexGuard aGuard;
693 :
694 0 : const sal_Int32 nParas( mpImpl->GetParagraphCount() );
695 : sal_Int32 nIndex;
696 : int i;
697 0 : for( i=0; i<nParas; ++i )
698 : {
699 : // TODO: maybe exploit the fact that paragraphs are
700 : // ordered vertically for early exit
701 :
702 : // #i70916# Text in spread sheet cells return the wrong extents
703 0 : AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i );
704 0 : awt::Rectangle aParaBounds( rPara.getBounds() );
705 0 : awt::Point aPoint( rPoint );
706 0 : aPoint.X -= aParaBounds.X;
707 0 : aPoint.Y -= aParaBounds.Y;
708 :
709 : // #112814# Use correct index offset
710 0 : if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 )
711 0 : return mpImpl->Internal2Index( EPosition(sal::static_int_cast<sal_uInt16>(i),
712 0 : sal::static_int_cast<sal_uInt16>(nIndex)) );
713 : }
714 :
715 0 : return -1;
716 : }
717 :
718 0 : OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException)
719 : {
720 0 : SolarMutexGuard aGuard;
721 :
722 0 : sal_Int32 nStart( getSelectionStart() );
723 0 : sal_Int32 nEnd( getSelectionEnd() );
724 :
725 : // #104481# Return the empty string for 'no selection'
726 0 : if( nStart < 0 || nEnd < 0 )
727 0 : return OUString();
728 :
729 0 : return getTextRange( nStart, nEnd );
730 : }
731 :
732 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException)
733 : {
734 0 : SolarMutexGuard aGuard;
735 :
736 : sal_Int32 i, nPos, nParas;
737 0 : for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
738 : {
739 0 : if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 )
740 0 : return nPos;
741 : }
742 :
743 0 : return nPos;
744 : }
745 :
746 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException)
747 : {
748 0 : SolarMutexGuard aGuard;
749 :
750 : sal_Int32 i, nPos, nParas;
751 0 : for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
752 : {
753 0 : if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 )
754 0 : return nPos;
755 : }
756 :
757 0 : return nPos;
758 : }
759 :
760 0 : sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
761 : {
762 0 : SolarMutexGuard aGuard;
763 :
764 0 : EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
765 0 : EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
766 :
767 : return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex,
768 0 : aEndIndex.nPara, aEndIndex.nIndex );
769 : }
770 :
771 0 : OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException)
772 : {
773 0 : SolarMutexGuard aGuard;
774 :
775 : sal_Int32 i, nParas;
776 0 : OUString aRes;
777 0 : for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
778 0 : aRes += mpImpl->GetParagraph(i).getText();
779 :
780 0 : return aRes;
781 : }
782 :
783 0 : OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
784 : {
785 0 : SolarMutexGuard aGuard;
786 :
787 0 : if( nStartIndex > nEndIndex )
788 0 : ::std::swap(nStartIndex, nEndIndex);
789 :
790 0 : EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
791 0 : EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
792 :
793 : // #102170# Special case: start and end paragraph are identical
794 0 : if( aStartIndex.nPara == aEndIndex.nPara )
795 : {
796 0 : return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
797 : }
798 : else
799 : {
800 0 : sal_Int32 i( aStartIndex.nPara );
801 0 : OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
802 0 : mpImpl->GetParagraph(i).getCharacterCount()-1) );
803 0 : ++i;
804 :
805 : // paragraphs inbetween are fully included
806 0 : for( ; i<aEndIndex.nPara; ++i )
807 0 : aRes += mpImpl->GetParagraph(i).getText();
808 :
809 0 : if( i<=aEndIndex.nPara )
810 0 : aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
811 :
812 0 : return aRes;
813 0 : }
814 : }
815 :
816 0 : ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
817 : {
818 0 : SolarMutexGuard aGuard;
819 :
820 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
821 :
822 0 : ::com::sun::star::accessibility::TextSegment aResult;
823 :
824 0 : if( AccessibleTextType::PARAGRAPH == aTextType )
825 : {
826 : // #106393# Special casing one behind last paragraph is
827 : // not necessary, since then, we return the content and
828 : // boundary of that last paragraph. Range2Internal is
829 : // tolerant against that, and returns the last paragraph
830 : // in aPos.nPara.
831 :
832 : // retrieve full text of the paragraph
833 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
834 :
835 : // #112814# Adapt the start index with the paragraph offset
836 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
837 0 : aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
838 : }
839 : else
840 : {
841 : // No special handling required, forward to wrapped class
842 0 : aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
843 :
844 : // #112814# Adapt the start index with the paragraph offset
845 0 : mpImpl->CorrectTextSegment( aResult, aPos.nPara );
846 : }
847 :
848 0 : return aResult;
849 : }
850 :
851 0 : ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
852 : {
853 0 : SolarMutexGuard aGuard;
854 :
855 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
856 :
857 0 : ::com::sun::star::accessibility::TextSegment aResult;
858 :
859 0 : if( AccessibleTextType::PARAGRAPH == aTextType )
860 : {
861 0 : if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
862 : {
863 : // #103589# Special casing one behind the last paragraph
864 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
865 :
866 : // #112814# Adapt the start index with the paragraph offset
867 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
868 : }
869 0 : else if( aPos.nPara > 0 )
870 : {
871 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
872 :
873 : // #112814# Adapt the start index with the paragraph offset
874 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
875 : }
876 :
877 0 : aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
878 : }
879 : else
880 : {
881 : // No special handling required, forward to wrapped class
882 0 : aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
883 :
884 : // #112814# Adapt the start index with the paragraph offset
885 0 : mpImpl->CorrectTextSegment( aResult, aPos.nPara );
886 : }
887 :
888 0 : return aResult;
889 : }
890 :
891 0 : ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
892 : {
893 0 : SolarMutexGuard aGuard;
894 :
895 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
896 :
897 0 : ::com::sun::star::accessibility::TextSegment aResult;
898 :
899 0 : if( AccessibleTextType::PARAGRAPH == aTextType )
900 : {
901 : // Special casing one behind the last paragraph is not
902 : // necessary, this case is invalid here for
903 : // getTextBehindIndex
904 0 : if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
905 : {
906 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
907 :
908 : // #112814# Adapt the start index with the paragraph offset
909 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
910 0 : aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
911 : }
912 : }
913 : else
914 : {
915 : // No special handling required, forward to wrapped class
916 0 : aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
917 :
918 : // #112814# Adapt the start index with the paragraph offset
919 0 : mpImpl->CorrectTextSegment( aResult, aPos.nPara );
920 : }
921 :
922 0 : return aResult;
923 : }
924 :
925 0 : sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
926 : {
927 0 : SolarMutexGuard aGuard;
928 :
929 0 : if( nStartIndex > nEndIndex )
930 0 : ::std::swap(nStartIndex, nEndIndex);
931 :
932 0 : EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
933 0 : EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
934 :
935 : return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
936 0 : aEndIndex.nPara, aEndIndex.nIndex );
937 : }
938 :
939 : // XAccessibleTextAttributes
940 0 : uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< OUString >& RequestedAttributes ) throw (uno::RuntimeException)
941 : {
942 : // get the intersection of the default attributes of all paragraphs
943 :
944 0 : SolarMutexGuard aGuard;
945 :
946 0 : PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
947 :
948 0 : const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
949 0 : for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
950 : {
951 0 : uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
952 0 : PropertyValueVector aIntersectionVec;
953 :
954 0 : PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
955 0 : for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
956 : {
957 0 : const beans::PropertyValue* pItr = aSeq.getConstArray();
958 0 : const beans::PropertyValue* pEnd = pItr + aSeq.getLength();
959 0 : const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
960 0 : if ( pFind != pEnd )
961 : {
962 0 : aIntersectionVec.push_back( *pFind );
963 : }
964 : }
965 :
966 0 : aDefAttrVec.swap( aIntersectionVec );
967 :
968 0 : if ( aDefAttrVec.empty() )
969 : {
970 0 : break;
971 : }
972 0 : }
973 :
974 0 : return aDefAttrVec.getAsConstList();
975 : }
976 :
977 0 : uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
978 : {
979 : // get those default attributes of the paragraph, which are not part
980 : // of the intersection of all paragraphs and add them to the run attributes
981 :
982 0 : SolarMutexGuard aGuard;
983 :
984 0 : EPosition aPos( mpImpl->Index2Internal( nIndex ) );
985 0 : AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
986 0 : uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
987 0 : uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
988 0 : uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
989 0 : PropertyValueVector aDiffVec;
990 :
991 0 : const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
992 0 : const sal_Int32 nLength = aDefAttrSeq.getLength();
993 0 : for ( sal_Int32 i = 0; i < nLength; ++i )
994 : {
995 0 : const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
996 0 : const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength();
997 0 : const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
998 0 : if ( pFind == pEnd && pDefAttr[i].Handle != 0)
999 : {
1000 0 : aDiffVec.push_back( pDefAttr[i] );
1001 : }
1002 : }
1003 :
1004 0 : return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
1005 : }
1006 :
1007 0 : Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1008 : {
1009 0 : return mpImpl->GetParagraphBoundingBox();
1010 : }
1011 :
1012 267 : } // end of namespace accessibility
1013 :
1014 : //------------------------------------------------------------------------
1015 :
1016 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|