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 <= USHRT_MAX &&
90 : nStartIndex >= 0 && nStartIndex <= USHRT_MAX &&
91 : nEndPara >= 0 && nEndPara <= USHRT_MAX &&
92 : nEndIndex >= 0 && nEndIndex <= USHRT_MAX ,
93 : "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow");
94 :
95 : return ESelection( static_cast< sal_uInt16 >(nStartPara), static_cast< sal_uInt16 >(nStartIndex),
96 0 : static_cast< sal_uInt16 >(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 0 : void SetEventSource( const uno::Reference< XAccessible >& rInterface )
135 : {
136 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
137 :
138 0 : mxThis = rInterface;
139 0 : }
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 0 : AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() :
224 : mxThis( NULL ),
225 0 : mpTextParagraph( new AccessibleEditableTextPara(NULL) ),
226 : mxParagraph( mpTextParagraph ),
227 : maEditSource(),
228 : maMutex(),
229 0 : 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 0 : }
236 :
237 0 : AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl()
238 : {
239 : DBG_DTOR( AccessibleStaticTextBase_Impl, NULL );
240 0 : }
241 :
242 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
243 0 : void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
244 : {
245 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
246 :
247 0 : maEditSource.SetEditSource( pEditSource );
248 0 : if( mpTextParagraph )
249 0 : mpTextParagraph->SetEditSource( &maEditSource );
250 0 : }
251 : SAL_WNODEPRECATED_DECLARATIONS_POP
252 :
253 0 : 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 0 : ::osl::MutexGuard aGuard( maMutex );
260 0 : maOffset = rPoint;
261 : }
262 :
263 0 : if( mpTextParagraph )
264 0 : mpTextParagraph->SetEEOffset( rPoint );
265 :
266 : // in all cases, check visibility afterwards.
267 0 : UpdateChildren();
268 0 : }
269 :
270 0 : void AccessibleStaticTextBase_Impl::UpdateChildren()
271 : {
272 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
273 :
274 : // currently no children
275 0 : }
276 :
277 0 : 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 0 : if( mpTextParagraph )
283 0 : mpTextParagraph->Dispose();
284 :
285 : // drop references
286 0 : mxParagraph = NULL;
287 0 : mxThis = NULL;
288 0 : mpTextParagraph = NULL;
289 0 : }
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 : throw lang::DisposedException (
304 0 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), mxThis );
305 :
306 : // TODO: Have a differnt method on AccessibleEditableTextPara
307 : // that does not care about state changes
308 0 : mpTextParagraph->SetParagraphIndex( nPara );
309 :
310 0 : return *mpTextParagraph;
311 : }
312 :
313 0 : sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const
314 : {
315 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
316 :
317 0 : if( !mpTextParagraph )
318 0 : return 0;
319 : else
320 0 : return mpTextParagraph->GetTextForwarder().GetParagraphCount();
321 : }
322 :
323 0 : sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const
324 : {
325 0 : sal_Int32 aRes(0);
326 : int i;
327 0 : for(i=0; i<nEEIndex.nPara; ++i)
328 0 : aRes += GetParagraph(i).getCharacterCount();
329 :
330 0 : return aRes + nEEIndex.nIndex;
331 : }
332 :
333 0 : void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment,
334 : int nPara ) const
335 : {
336 : // Keep 'invalid' values at the TextSegment
337 0 : if( aTextSegment.SegmentStart != -1 &&
338 : aTextSegment.SegmentEnd != -1 )
339 : {
340 : // #112814# Correct TextSegment by paragraph offset
341 0 : sal_Int32 nOffset(0);
342 : int i;
343 0 : for(i=0; i<nPara; ++i)
344 0 : nOffset += GetParagraph(i).getCharacterCount();
345 :
346 0 : aTextSegment.SegmentStart += nOffset;
347 0 : aTextSegment.SegmentEnd += nOffset;
348 : }
349 0 : }
350 :
351 0 : EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const
352 : {
353 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
354 :
355 0 : if( nFlatIndex < 0 )
356 : throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
357 0 : mxThis);
358 : // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually
359 :
360 : sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount;
361 0 : for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara )
362 : {
363 0 : nCurrCount = GetParagraph( nCurrPara ).getCharacterCount();
364 0 : nCurrIndex += nCurrCount;
365 :
366 0 : if( nCurrIndex > nFlatIndex )
367 : {
368 : // check overflow
369 : DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
370 : nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
371 : "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
372 :
373 0 : return EPosition( static_cast< sal_uInt16 >(nCurrPara), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
374 : }
375 : }
376 :
377 : // #102170# Allow one-past the end for ranges
378 0 : if( bExclusive && nCurrIndex == nFlatIndex )
379 : {
380 : // check overflow
381 : DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX &&
382 : nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX ,
383 : "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow");
384 :
385 0 : return EPosition( static_cast< sal_uInt16 >(nCurrPara-1), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) );
386 : }
387 :
388 : // not found? Out of bounds
389 : throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")),
390 0 : mxThis);
391 : }
392 :
393 0 : sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex,
394 : sal_Int32 nEndPara, sal_Int32 nEndIndex )
395 : {
396 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
397 :
398 0 : if( !mpTextParagraph )
399 0 : return sal_False;
400 :
401 : try
402 : {
403 0 : SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
404 0 : return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
405 : }
406 0 : catch( const uno::RuntimeException& )
407 : {
408 0 : return sal_False;
409 : }
410 : }
411 :
412 0 : sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex,
413 : sal_Int32 nEndPara, sal_Int32 nEndIndex )
414 : {
415 : DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL );
416 :
417 0 : if( !mpTextParagraph )
418 0 : return sal_False;
419 :
420 : try
421 : {
422 0 : SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True );
423 0 : mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs
424 : sal_Bool aRetVal;
425 :
426 : // save current selection
427 0 : ESelection aOldSelection;
428 :
429 0 : rCacheVF.GetSelection( aOldSelection );
430 0 : rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) );
431 0 : aRetVal = rCacheVF.Copy();
432 0 : rCacheVF.SetSelection( aOldSelection ); // restore
433 :
434 0 : return aRetVal;
435 : }
436 0 : catch( const uno::RuntimeException& )
437 : {
438 0 : return sal_False;
439 : }
440 : }
441 :
442 0 : Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const
443 : {
444 0 : Rectangle aRect;
445 0 : if( mpTextParagraph )
446 : {
447 0 : awt::Rectangle aAwtRect = mpTextParagraph->getBounds();
448 0 : aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) );
449 : }
450 : else
451 : {
452 0 : aRect.SetEmpty();
453 : }
454 0 : return aRect;
455 : }
456 :
457 : //------------------------------------------------------------------------
458 : //
459 : // AccessibleStaticTextBase implementation
460 : //
461 : //------------------------------------------------------------------------
462 :
463 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
464 0 : AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) :
465 0 : mpImpl( new AccessibleStaticTextBase_Impl() )
466 : {
467 0 : SolarMutexGuard aGuard;
468 :
469 0 : SetEditSource( pEditSource );
470 0 : }
471 : SAL_WNODEPRECATED_DECLARATIONS_POP
472 :
473 0 : AccessibleStaticTextBase::~AccessibleStaticTextBase()
474 : {
475 0 : }
476 :
477 0 : const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException))
478 : {
479 : #ifdef DBG_UTIL
480 : mpImpl->CheckInvariants();
481 :
482 : const SvxEditSource& aEditSource = mpImpl->GetEditSource();
483 :
484 : mpImpl->CheckInvariants();
485 :
486 : return aEditSource;
487 : #else
488 0 : return mpImpl->GetEditSource();
489 : #endif
490 : }
491 :
492 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
493 0 : void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException))
494 : {
495 : #ifdef DBG_UTIL
496 : // precondition: solar mutex locked
497 : DBG_TESTSOLARMUTEX();
498 :
499 : mpImpl->CheckInvariants();
500 :
501 : mpImpl->SetEditSource( pEditSource );
502 :
503 : mpImpl->CheckInvariants();
504 : #else
505 0 : mpImpl->SetEditSource( pEditSource );
506 : #endif
507 0 : }
508 : SAL_WNODEPRECATED_DECLARATIONS_POP
509 :
510 0 : void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface )
511 : {
512 : #ifdef DBG_UTIL
513 : mpImpl->CheckInvariants();
514 : #endif
515 :
516 0 : mpImpl->SetEventSource( rInterface );
517 :
518 : #ifdef DBG_UTIL
519 : mpImpl->CheckInvariants();
520 : #endif
521 0 : }
522 :
523 0 : uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const
524 : {
525 : #ifdef DBG_UTIL
526 : mpImpl->CheckInvariants();
527 :
528 : uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
529 :
530 : mpImpl->CheckInvariants();
531 :
532 : return xRet;
533 : #else
534 0 : return mpImpl->GetEventSource();
535 : #endif
536 : }
537 :
538 0 : void AccessibleStaticTextBase::SetOffset( const Point& rPoint )
539 : {
540 : #ifdef DBG_UTIL
541 : // precondition: solar mutex locked
542 : DBG_TESTSOLARMUTEX();
543 :
544 : mpImpl->CheckInvariants();
545 :
546 : mpImpl->SetOffset( rPoint );
547 :
548 : mpImpl->CheckInvariants();
549 : #else
550 0 : mpImpl->SetOffset( rPoint );
551 : #endif
552 0 : }
553 :
554 0 : Point AccessibleStaticTextBase::GetOffset() const
555 : {
556 : #ifdef DBG_UTIL
557 : mpImpl->CheckInvariants();
558 :
559 : Point aPoint( mpImpl->GetOffset() );
560 :
561 : mpImpl->CheckInvariants();
562 :
563 : return aPoint;
564 : #else
565 0 : return mpImpl->GetOffset();
566 : #endif
567 : }
568 :
569 0 : void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
570 : {
571 : #ifdef DBG_UTIL
572 : // precondition: solar mutex locked
573 : DBG_TESTSOLARMUTEX();
574 :
575 : mpImpl->CheckInvariants();
576 :
577 : mpImpl->UpdateChildren();
578 :
579 : mpImpl->CheckInvariants();
580 : #else
581 0 : mpImpl->UpdateChildren();
582 : #endif
583 0 : }
584 :
585 0 : void AccessibleStaticTextBase::Dispose()
586 : {
587 : #ifdef DBG_UTIL
588 : mpImpl->CheckInvariants();
589 : #endif
590 :
591 0 : mpImpl->Dispose();
592 :
593 : #ifdef DBG_UTIL
594 : mpImpl->CheckInvariants();
595 : #endif
596 0 : }
597 :
598 : // XAccessibleContext
599 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException)
600 : {
601 : // no children at all
602 0 : return 0;
603 : }
604 :
605 0 : uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
606 : {
607 : // no children at all
608 0 : return uno::Reference< XAccessible >();
609 : }
610 :
611 0 : uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException)
612 : {
613 : // no children at all
614 0 : return uno::Reference< XAccessible >();
615 : }
616 :
617 : // XAccessibleText
618 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException)
619 : {
620 0 : SolarMutexGuard aGuard;
621 :
622 : sal_Int32 i, nPos, nParas;
623 0 : for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
624 : {
625 0 : if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 )
626 0 : return nPos;
627 : }
628 :
629 0 : return nPos;
630 : }
631 :
632 0 : sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
633 : {
634 0 : return setSelection(nIndex, nIndex);
635 : }
636 :
637 0 : sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
638 : {
639 0 : SolarMutexGuard aGuard;
640 :
641 0 : EPosition aPos( mpImpl->Index2Internal(nIndex) );
642 :
643 0 : return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex );
644 : }
645 :
646 0 : uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
647 : {
648 0 : SolarMutexGuard aGuard;
649 :
650 0 : EPosition aPos( mpImpl->Index2Internal(nIndex) );
651 :
652 0 : return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes );
653 : }
654 :
655 0 : awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
656 : {
657 0 : SolarMutexGuard aGuard;
658 :
659 : // #108900# Allow ranges for nIndex, as one-past-the-end
660 : // values are now legal, too.
661 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
662 :
663 : // #i70916# Text in spread sheet cells return the wrong extents
664 0 : AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
665 0 : awt::Rectangle aParaBounds( rPara.getBounds() );
666 0 : awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) );
667 0 : aBounds.X += aParaBounds.X;
668 0 : aBounds.Y += aParaBounds.Y;
669 :
670 0 : return aBounds;
671 : }
672 :
673 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException)
674 : {
675 0 : SolarMutexGuard aGuard;
676 :
677 : sal_Int32 i, nCount, nParas;
678 0 : for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
679 0 : nCount += mpImpl->GetParagraph(i).getCharacterCount();
680 :
681 0 : return nCount;
682 : }
683 :
684 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException)
685 : {
686 0 : SolarMutexGuard aGuard;
687 :
688 0 : const sal_Int32 nParas( mpImpl->GetParagraphCount() );
689 : sal_Int32 nIndex;
690 : int i;
691 0 : for( i=0; i<nParas; ++i )
692 : {
693 : // TODO: maybe exploit the fact that paragraphs are
694 : // ordered vertically for early exit
695 :
696 : // #i70916# Text in spread sheet cells return the wrong extents
697 0 : AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i );
698 0 : awt::Rectangle aParaBounds( rPara.getBounds() );
699 0 : awt::Point aPoint( rPoint );
700 0 : aPoint.X -= aParaBounds.X;
701 0 : aPoint.Y -= aParaBounds.Y;
702 :
703 : // #112814# Use correct index offset
704 0 : if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 )
705 0 : return mpImpl->Internal2Index( EPosition(sal::static_int_cast<sal_uInt16>(i),
706 0 : sal::static_int_cast<sal_uInt16>(nIndex)) );
707 : }
708 :
709 0 : return -1;
710 : }
711 :
712 0 : ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException)
713 : {
714 0 : SolarMutexGuard aGuard;
715 :
716 0 : sal_Int32 nStart( getSelectionStart() );
717 0 : sal_Int32 nEnd( getSelectionEnd() );
718 :
719 : // #104481# Return the empty string for 'no selection'
720 0 : if( nStart < 0 || nEnd < 0 )
721 0 : return ::rtl::OUString();
722 :
723 0 : return getTextRange( nStart, nEnd );
724 : }
725 :
726 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException)
727 : {
728 0 : SolarMutexGuard aGuard;
729 :
730 : sal_Int32 i, nPos, nParas;
731 0 : for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
732 : {
733 0 : if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 )
734 0 : return nPos;
735 : }
736 :
737 0 : return nPos;
738 : }
739 :
740 0 : sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException)
741 : {
742 0 : SolarMutexGuard aGuard;
743 :
744 : sal_Int32 i, nPos, nParas;
745 0 : for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
746 : {
747 0 : if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 )
748 0 : return nPos;
749 : }
750 :
751 0 : return nPos;
752 : }
753 :
754 0 : sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
755 : {
756 0 : SolarMutexGuard aGuard;
757 :
758 0 : EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
759 0 : EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
760 :
761 : return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex,
762 0 : aEndIndex.nPara, aEndIndex.nIndex );
763 : }
764 :
765 0 : ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException)
766 : {
767 0 : SolarMutexGuard aGuard;
768 :
769 : sal_Int32 i, nParas;
770 0 : ::rtl::OUString aRes;
771 0 : for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i )
772 0 : aRes += mpImpl->GetParagraph(i).getText();
773 :
774 0 : return aRes;
775 : }
776 :
777 0 : ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
778 : {
779 0 : SolarMutexGuard aGuard;
780 :
781 0 : if( nStartIndex > nEndIndex )
782 0 : ::std::swap(nStartIndex, nEndIndex);
783 :
784 0 : EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
785 0 : EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
786 :
787 : // #102170# Special case: start and end paragraph are identical
788 0 : if( aStartIndex.nPara == aEndIndex.nPara )
789 : {
790 0 : return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex );
791 : }
792 : else
793 : {
794 0 : sal_Int32 i( aStartIndex.nPara );
795 0 : ::rtl::OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex,
796 0 : mpImpl->GetParagraph(i).getCharacterCount()-1) );
797 0 : ++i;
798 :
799 : // paragraphs inbetween are fully included
800 0 : for( ; i<aEndIndex.nPara; ++i )
801 0 : aRes += mpImpl->GetParagraph(i).getText();
802 :
803 0 : if( i<=aEndIndex.nPara )
804 0 : aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex );
805 :
806 0 : return aRes;
807 0 : }
808 : }
809 :
810 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)
811 : {
812 0 : SolarMutexGuard aGuard;
813 :
814 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
815 :
816 0 : ::com::sun::star::accessibility::TextSegment aResult;
817 :
818 0 : if( AccessibleTextType::PARAGRAPH == aTextType )
819 : {
820 : // #106393# Special casing one behind last paragraph is
821 : // not necessary, since then, we return the content and
822 : // boundary of that last paragraph. Range2Internal is
823 : // tolerant against that, and returns the last paragraph
824 : // in aPos.nPara.
825 :
826 : // retrieve full text of the paragraph
827 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
828 :
829 : // #112814# Adapt the start index with the paragraph offset
830 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
831 0 : aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
832 : }
833 : else
834 : {
835 : // No special handling required, forward to wrapped class
836 0 : aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType );
837 :
838 : // #112814# Adapt the start index with the paragraph offset
839 0 : mpImpl->CorrectTextSegment( aResult, aPos.nPara );
840 : }
841 :
842 0 : return aResult;
843 : }
844 :
845 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)
846 : {
847 0 : SolarMutexGuard aGuard;
848 :
849 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
850 :
851 0 : ::com::sun::star::accessibility::TextSegment aResult;
852 :
853 0 : if( AccessibleTextType::PARAGRAPH == aTextType )
854 : {
855 0 : if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() )
856 : {
857 : // #103589# Special casing one behind the last paragraph
858 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText();
859 :
860 : // #112814# Adapt the start index with the paragraph offset
861 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) );
862 : }
863 0 : else if( aPos.nPara > 0 )
864 : {
865 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText();
866 :
867 : // #112814# Adapt the start index with the paragraph offset
868 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) );
869 : }
870 :
871 0 : aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
872 : }
873 : else
874 : {
875 : // No special handling required, forward to wrapped class
876 0 : aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType );
877 :
878 : // #112814# Adapt the start index with the paragraph offset
879 0 : mpImpl->CorrectTextSegment( aResult, aPos.nPara );
880 : }
881 :
882 0 : return aResult;
883 : }
884 :
885 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)
886 : {
887 0 : SolarMutexGuard aGuard;
888 :
889 0 : EPosition aPos( mpImpl->Range2Internal(nIndex) );
890 :
891 0 : ::com::sun::star::accessibility::TextSegment aResult;
892 :
893 0 : if( AccessibleTextType::PARAGRAPH == aTextType )
894 : {
895 : // Special casing one behind the last paragraph is not
896 : // necessary, this case is invalid here for
897 : // getTextBehindIndex
898 0 : if( aPos.nPara + 1 < mpImpl->GetParagraphCount() )
899 : {
900 0 : aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText();
901 :
902 : // #112814# Adapt the start index with the paragraph offset
903 0 : aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) );
904 0 : aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
905 : }
906 : }
907 : else
908 : {
909 : // No special handling required, forward to wrapped class
910 0 : aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType );
911 :
912 : // #112814# Adapt the start index with the paragraph offset
913 0 : mpImpl->CorrectTextSegment( aResult, aPos.nPara );
914 : }
915 :
916 0 : return aResult;
917 : }
918 :
919 0 : sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
920 : {
921 0 : SolarMutexGuard aGuard;
922 :
923 0 : if( nStartIndex > nEndIndex )
924 0 : ::std::swap(nStartIndex, nEndIndex);
925 :
926 0 : EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) );
927 0 : EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) );
928 :
929 : return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex,
930 0 : aEndIndex.nPara, aEndIndex.nIndex );
931 : }
932 :
933 : // XAccessibleTextAttributes
934 0 : uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException)
935 : {
936 : // get the intersection of the default attributes of all paragraphs
937 :
938 0 : SolarMutexGuard aGuard;
939 :
940 0 : PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) );
941 :
942 0 : const sal_Int32 nParaCount = mpImpl->GetParagraphCount();
943 0 : for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara )
944 : {
945 0 : uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes );
946 0 : PropertyValueVector aIntersectionVec;
947 :
948 0 : PropertyValueVector::const_iterator aEnd = aDefAttrVec.end();
949 0 : for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr )
950 : {
951 0 : const beans::PropertyValue* pItr = aSeq.getConstArray();
952 0 : const beans::PropertyValue* pEnd = pItr + aSeq.getLength();
953 0 : const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) );
954 0 : if ( pFind != pEnd )
955 : {
956 0 : aIntersectionVec.push_back( *pFind );
957 : }
958 : }
959 :
960 0 : aDefAttrVec.swap( aIntersectionVec );
961 :
962 0 : if ( aDefAttrVec.empty() )
963 : {
964 : break;
965 : }
966 0 : }
967 :
968 0 : return aDefAttrVec.getAsConstList();
969 : }
970 :
971 0 : uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
972 : {
973 : // get those default attributes of the paragraph, which are not part
974 : // of the intersection of all paragraphs and add them to the run attributes
975 :
976 0 : SolarMutexGuard aGuard;
977 :
978 0 : EPosition aPos( mpImpl->Index2Internal( nIndex ) );
979 0 : AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara );
980 0 : uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes );
981 0 : uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes );
982 0 : uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes );
983 0 : PropertyValueVector aDiffVec;
984 :
985 0 : const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray();
986 0 : const sal_Int32 nLength = aDefAttrSeq.getLength();
987 0 : for ( sal_Int32 i = 0; i < nLength; ++i )
988 : {
989 0 : const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray();
990 0 : const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength();
991 0 : const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) );
992 0 : if ( pFind == pEnd && pDefAttr[i].Handle != 0)
993 : {
994 0 : aDiffVec.push_back( pDefAttr[i] );
995 : }
996 : }
997 :
998 0 : return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() );
999 : }
1000 :
1001 0 : Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const
1002 : {
1003 0 : return mpImpl->GetParagraphBoundingBox();
1004 : }
1005 :
1006 : } // end of namespace accessibility
1007 :
1008 : //------------------------------------------------------------------------
1009 :
1010 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|