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 <memory>
29 : #include <algorithm>
30 : #include <deque>
31 : #include <osl/mutex.hxx>
32 : #include <com/sun/star/uno/Any.hxx>
33 : #include <com/sun/star/uno/Reference.hxx>
34 : #include <cppuhelper/weakref.hxx>
35 : #include <com/sun/star/awt/Point.hpp>
36 : #include <com/sun/star/awt/Rectangle.hpp>
37 : #include <com/sun/star/lang/DisposedException.hpp>
38 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
39 : #include <com/sun/star/accessibility/XAccessible.hpp>
40 : #include <com/sun/star/accessibility/XAccessibleContext.hpp>
41 : #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
42 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
43 : #include <comphelper/accessibleeventnotifier.hxx>
44 : #include <unotools/accessiblestatesethelper.hxx>
45 : #include <vcl/unohelp.hxx>
46 : #include <vcl/svapp.hxx>
47 :
48 : //------------------------------------------------------------------------
49 : //
50 : // Project-local header
51 : //
52 : //------------------------------------------------------------------------
53 : #include "AccessibleTextEventQueue.hxx"
54 : #include <svx/AccessibleTextHelper.hxx>
55 : #include <svx/unoshape.hxx>
56 : #include "editeng/unolingu.hxx"
57 : #include <editeng/unotext.hxx>
58 :
59 : #include "editeng/unoedhlp.hxx"
60 : #include "editeng/unopracc.hxx"
61 : #include "editeng/AccessibleParaManager.hxx"
62 : #include "editeng/AccessibleEditableTextPara.hxx"
63 : #include <svx/svdmodel.hxx>
64 : #include <svx/svdpntv.hxx>
65 : #include <editeng/editdata.hxx>
66 : #include <editeng/editeng.hxx>
67 : #include <editeng/editview.hxx>
68 :
69 : using namespace ::com::sun::star;
70 : using namespace ::com::sun::star::accessibility;
71 :
72 : namespace accessibility
73 : {
74 :
75 : //------------------------------------------------------------------------
76 : //
77 : // AccessibleTextHelper_Impl declaration
78 : //
79 : //------------------------------------------------------------------------
80 :
81 : DBG_NAME( AccessibleTextHelper_Impl )
82 :
83 : template < typename first_type, typename second_type >
84 0 : ::std::pair< first_type, second_type > makeSortedPair( first_type first,
85 : second_type second )
86 : {
87 0 : if( first > second )
88 0 : return ::std::make_pair( second, first );
89 : else
90 0 : return ::std::make_pair( first, second );
91 : }
92 :
93 : class AccessibleTextHelper_Impl : public SfxListener
94 : {
95 :
96 : public:
97 : typedef ::std::vector< sal_Int16 > VectorOfStates;
98 :
99 : // receive pointer to our frontend class and view window
100 : AccessibleTextHelper_Impl();
101 : ~AccessibleTextHelper_Impl();
102 :
103 : // XAccessibleContext child handling methods
104 : sal_Int32 SAL_CALL getAccessibleChildCount() SAL_THROW((uno::RuntimeException));
105 : uno::Reference< XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException));
106 :
107 : // XAccessibleEventBroadcaster child related methods
108 : void SAL_CALL addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
109 : void SAL_CALL removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException));
110 :
111 : // XAccessibleComponent child related methods
112 : uno::Reference< XAccessible > SAL_CALL getAccessibleAtPoint( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException));
113 :
114 : SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException));
115 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
116 : void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException));
117 : SAL_WNODEPRECATED_DECLARATIONS_POP
118 :
119 0 : void SetEventSource( const uno::Reference< XAccessible >& rInterface )
120 : {
121 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
122 0 : mxFrontEnd = rInterface;
123 0 : }
124 0 : uno::Reference< XAccessible > GetEventSource() const
125 : {
126 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
127 0 : return mxFrontEnd;
128 : }
129 :
130 : void SetOffset( const Point& );
131 0 : Point GetOffset() const
132 : {
133 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
134 0 : ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset );
135 0 : return aPoint;
136 : }
137 :
138 : void SetStartIndex( sal_Int32 nOffset );
139 0 : sal_Int32 GetStartIndex() const
140 : {
141 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
142 : // Strictly correct only with locked solar mutex, // but
143 : // here we rely on the fact that sal_Int32 access is
144 : // atomic
145 0 : return mnStartIndex;
146 : }
147 :
148 : void SetAdditionalChildStates( const VectorOfStates& rChildStates );
149 :
150 : sal_Bool IsSelected() const;
151 :
152 : void Dispose();
153 :
154 : // do NOT hold object mutex when calling this! Danger of deadlock
155 : void FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue = uno::Any(), const uno::Any& rOldValue = uno::Any() ) const;
156 : void FireEvent( const AccessibleEventObject& rEvent ) const;
157 :
158 : void SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
159 : sal_Bool HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException));
160 : void SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
161 : void SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException));
162 : void ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException));
163 :
164 : #ifdef DBG_UTIL
165 : void CheckInvariants() const;
166 : #endif
167 :
168 : // checks all children for visibility, throws away invisible ones
169 : void UpdateVisibleChildren( bool bBroadcastEvents=true );
170 :
171 : // check all children for changes in position and size
172 : void UpdateBoundRect();
173 :
174 : // calls SetSelection on the forwarder and updates maLastSelection
175 : // cache.
176 : void UpdateSelection();
177 :
178 : private:
179 :
180 : // Process event queue
181 : void ProcessQueue();
182 :
183 : // syntactic sugar for FireEvent
184 0 : void GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, rNewValue ); }
185 0 : void LostPropertyEvent( const uno::Any& rOldValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, uno::Any(), rOldValue ); }
186 :
187 : // shutdown usage of current edit source on myself and the children.
188 : void ShutdownEditSource() SAL_THROW((uno::RuntimeException));
189 :
190 : void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast );
191 :
192 : virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
193 :
194 0 : int getNotifierClientId() const { return mnNotifierClientId; }
195 :
196 : // lock solar mutex before
197 : SvxTextForwarder& GetTextForwarder() const SAL_THROW((uno::RuntimeException));
198 : // lock solar mutex before
199 : SvxViewForwarder& GetViewForwarder() const SAL_THROW((uno::RuntimeException));
200 : // lock solar mutex before
201 : SvxEditViewForwarder& GetEditViewForwarder( sal_Bool bCreate = sal_False ) const SAL_THROW((uno::RuntimeException));
202 :
203 : // are we in edit mode?
204 : sal_Bool IsActive() const SAL_THROW((uno::RuntimeException));
205 :
206 : // our frontend class (the one implementing the actual
207 : // interface). That's not necessarily the one containing the impl
208 : // pointer!
209 : uno::Reference< XAccessible > mxFrontEnd;
210 :
211 : // a wrapper for the text forwarders (guarded by solar mutex)
212 : mutable SvxEditSourceAdapter maEditSource;
213 :
214 : // store last selection (to correctly report selection changes, guarded by solar mutex)
215 : ESelection maLastSelection;
216 :
217 : // cache range of visible children (guarded by solar mutex)
218 : sal_Int32 mnFirstVisibleChild;
219 : sal_Int32 mnLastVisibleChild;
220 :
221 : // offset to add to all our children (unguarded, relying on
222 : // the fact that sal_Int32 access is atomic)
223 : sal_Int32 mnStartIndex;
224 :
225 : // the object handling our children (guarded by solar mutex)
226 : ::accessibility::AccessibleParaManager maParaManager;
227 :
228 : // number of not-yet-closed event frames (BEGIN/END sequences) (guarded by solar mutex)
229 : sal_Int32 maEventOpenFrames;
230 :
231 : // Queued events from Notify() (guarded by solar mutex)
232 : AccessibleTextEventQueue maEventQueue;
233 :
234 : // spin lock to prevent notify in notify (guarded by solar mutex)
235 : sal_Bool mbInNotify;
236 :
237 : // whether the object or it's children has the focus set (guarded by solar mutex)
238 : sal_Bool mbGroupHasFocus;
239 :
240 : // whether we (this object) has the focus set (guarded by solar mutex)
241 : sal_Bool mbThisHasFocus;
242 :
243 : mutable ::osl::Mutex maMutex;
244 :
245 : /// our current offset to the containing shape/cell (guarded by maMutex)
246 : Point maOffset;
247 :
248 : /// client Id from AccessibleEventNotifier
249 : int mnNotifierClientId;
250 : };
251 :
252 : //------------------------------------------------------------------------
253 : //
254 : // AccessibleTextHelper_Impl implementation
255 : //
256 : //------------------------------------------------------------------------
257 :
258 0 : AccessibleTextHelper_Impl::AccessibleTextHelper_Impl() :
259 : mxFrontEnd( NULL ),
260 : maLastSelection( EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND ),
261 : mnFirstVisibleChild( -1 ),
262 : mnLastVisibleChild( -2 ),
263 : mnStartIndex( 0 ),
264 : maEventOpenFrames( 0 ),
265 : mbInNotify( sal_False ),
266 : mbGroupHasFocus( sal_False ),
267 : mbThisHasFocus( sal_False ),
268 : maOffset(0,0),
269 : // well, that's strictly exception safe, though not really
270 : // robust. We rely on the fact that this member is constructed
271 : // last, and that the constructor body is empty, thus no
272 : // chance for exceptions once the Id is fetched. Nevertheless,
273 : // normally should employ RAII here...
274 0 : mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient())
275 : {
276 : DBG_CTOR( AccessibleTextHelper_Impl, NULL );
277 :
278 : #ifdef DBG_UTIL
279 : OSL_TRACE( "AccessibleTextHelper_Impl received ID: %d", mnNotifierClientId );
280 : #endif
281 0 : }
282 :
283 0 : AccessibleTextHelper_Impl::~AccessibleTextHelper_Impl()
284 : {
285 : DBG_DTOR( AccessibleTextHelper_Impl, NULL );
286 :
287 0 : SolarMutexGuard aGuard;
288 :
289 : try
290 : {
291 : // call Dispose here, too, since we've some resources not
292 : // automatically freed otherwise
293 0 : Dispose();
294 : }
295 0 : catch( const uno::Exception& ) {}
296 0 : }
297 :
298 0 : SvxTextForwarder& AccessibleTextHelper_Impl::GetTextForwarder() const SAL_THROW((uno::RuntimeException))
299 : {
300 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
301 :
302 0 : if( !maEditSource.IsValid() )
303 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
304 :
305 0 : SvxTextForwarder* pTextForwarder = maEditSource.GetTextForwarder();
306 :
307 0 : if( !pTextForwarder )
308 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, model might be dead")), mxFrontEnd);
309 :
310 0 : if( pTextForwarder->IsValid() )
311 0 : return *pTextForwarder;
312 : else
313 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Text forwarder is invalid, model might be dead")), mxFrontEnd);
314 : }
315 :
316 0 : SvxViewForwarder& AccessibleTextHelper_Impl::GetViewForwarder() const SAL_THROW((uno::RuntimeException))
317 : {
318 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
319 :
320 0 : if( !maEditSource.IsValid() )
321 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
322 :
323 0 : SvxViewForwarder* pViewForwarder = maEditSource.GetViewForwarder();
324 :
325 0 : if( !pViewForwarder )
326 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, model might be dead")), mxFrontEnd);
327 :
328 0 : if( pViewForwarder->IsValid() )
329 0 : return *pViewForwarder;
330 : else
331 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd);
332 : }
333 :
334 0 : SvxEditViewForwarder& AccessibleTextHelper_Impl::GetEditViewForwarder( sal_Bool bCreate ) const SAL_THROW((uno::RuntimeException))
335 : {
336 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
337 :
338 0 : if( !maEditSource.IsValid() )
339 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd);
340 :
341 0 : SvxEditViewForwarder* pViewForwarder = maEditSource.GetEditViewForwarder( bCreate );
342 :
343 0 : if( !pViewForwarder )
344 : {
345 0 : if( bCreate )
346 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch edit view forwarder, model might be dead")), mxFrontEnd);
347 : else
348 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No edit view forwarder, object not in edit mode")), mxFrontEnd);
349 : }
350 :
351 0 : if( pViewForwarder->IsValid() )
352 0 : return *pViewForwarder;
353 : else
354 : {
355 0 : if( bCreate )
356 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd);
357 : else
358 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object not in edit mode")), mxFrontEnd);
359 : }
360 : }
361 :
362 0 : SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const SAL_THROW((uno::RuntimeException))
363 : {
364 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
365 :
366 0 : if( maEditSource.IsValid() )
367 0 : return maEditSource;
368 : else
369 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::GetEditSource: no edit source")), mxFrontEnd );
370 : }
371 :
372 0 : sal_Bool AccessibleTextHelper_Impl::IsSelected() const
373 : {
374 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
375 :
376 0 : sal_Bool bRet = sal_False;
377 :
378 : try
379 : {
380 0 : ESelection aSelection;
381 0 : bRet = GetEditViewForwarder().GetSelection( aSelection );
382 : }
383 0 : catch( const uno::Exception& ) {}
384 :
385 0 : return bRet;
386 : }
387 :
388 : // functor for sending child events (no stand-alone function, they are maybe not inlined)
389 : class AccessibleTextHelper_OffsetChildIndex : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
390 : {
391 : public:
392 0 : AccessibleTextHelper_OffsetChildIndex( sal_Int32 nDifference ) : mnDifference(nDifference) {}
393 0 : void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
394 : {
395 0 : rPara.SetIndexInParent( rPara.GetIndexInParent() + mnDifference );
396 0 : }
397 :
398 : private:
399 : const sal_Int32 mnDifference;
400 : };
401 :
402 0 : void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset )
403 : {
404 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
405 :
406 0 : sal_Int32 nOldOffset( mnStartIndex );
407 :
408 0 : mnStartIndex = nOffset;
409 :
410 0 : if( nOldOffset != nOffset )
411 : {
412 : // update children
413 0 : AccessibleTextHelper_OffsetChildIndex aFunctor( nOffset - nOldOffset );
414 :
415 : ::std::for_each( maParaManager.begin(), maParaManager.end(),
416 0 : AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_OffsetChildIndex > (aFunctor) );
417 : }
418 0 : }
419 :
420 0 : void AccessibleTextHelper_Impl::SetAdditionalChildStates( const VectorOfStates& rChildStates )
421 : {
422 0 : maParaManager.SetAdditionalChildStates( rChildStates );
423 0 : }
424 :
425 0 : void AccessibleTextHelper_Impl::SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
426 : {
427 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
428 :
429 0 : if( bHaveFocus )
430 : {
431 0 : if( mbThisHasFocus )
432 0 : SetShapeFocus( sal_False );
433 :
434 0 : maParaManager.SetFocus( nChild );
435 :
436 : // we just received the focus, also send caret event then
437 0 : UpdateSelection();
438 :
439 : OSL_TRACE("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d received focus", nChild );
440 : }
441 : else
442 : {
443 0 : maParaManager.SetFocus( -1 );
444 :
445 : OSL_TRACE("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d lost focus", nChild );
446 :
447 0 : if( mbGroupHasFocus )
448 0 : SetShapeFocus( sal_True );
449 : }
450 0 : }
451 :
452 0 : void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException))
453 : {
454 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
455 :
456 0 : if( mbThisHasFocus )
457 0 : SetShapeFocus( sal_False );
458 :
459 0 : mbGroupHasFocus = sal_True;
460 0 : maParaManager.SetFocus( nNewChild );
461 :
462 : OSL_TRACE("AccessibleTextHelper_Impl::ChangeChildFocus(): Paragraph %d received focus", nNewChild );
463 0 : }
464 :
465 0 : void AccessibleTextHelper_Impl::SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
466 : {
467 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
468 :
469 0 : sal_Bool bOldFocus( mbThisHasFocus );
470 :
471 0 : mbThisHasFocus = bHaveFocus;
472 :
473 0 : if( bOldFocus != bHaveFocus )
474 : {
475 0 : if( bHaveFocus )
476 : {
477 0 : GotPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
478 : OSL_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object received focus" );
479 : }
480 : else
481 : {
482 0 : LostPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
483 : OSL_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object lost focus" );
484 : }
485 : }
486 0 : }
487 :
488 0 : void AccessibleTextHelper_Impl::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
489 : {
490 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
491 :
492 0 : sal_Bool bOldFocus( mbGroupHasFocus );
493 :
494 0 : mbGroupHasFocus = bHaveFocus;
495 :
496 0 : if( IsActive() )
497 : {
498 : try
499 : {
500 : // find the one with the cursor and get/set focus accordingly
501 0 : ESelection aSelection;
502 0 : if( GetEditViewForwarder().GetSelection( aSelection ) )
503 0 : SetChildFocus( aSelection.nEndPara, bHaveFocus );
504 : }
505 0 : catch( const uno::Exception& ) {}
506 : }
507 0 : else if( bOldFocus != bHaveFocus )
508 : {
509 0 : SetShapeFocus( bHaveFocus );
510 : }
511 :
512 : OSL_TRACE("AccessibleTextHelper_Impl::SetFocus: focus changed, Object %d, state: %s", this, bHaveFocus ? "focused" : "not focused");
513 0 : }
514 :
515 0 : sal_Bool AccessibleTextHelper_Impl::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
516 : {
517 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
518 :
519 : // No locking of solar mutex here, since we rely on the fact
520 : // that sal_Bool access is atomic
521 0 : return mbThisHasFocus;
522 : }
523 :
524 0 : sal_Bool AccessibleTextHelper_Impl::IsActive() const SAL_THROW((uno::RuntimeException))
525 : {
526 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
527 :
528 : try
529 : {
530 0 : SvxEditSource& rEditSource = GetEditSource();
531 0 : SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder();
532 :
533 0 : if( !pViewForwarder )
534 0 : return sal_False;
535 :
536 0 : if( pViewForwarder->IsValid() )
537 0 : return sal_True;
538 : else
539 0 : return sal_False;
540 : }
541 0 : catch( const uno::RuntimeException& )
542 : {
543 0 : return sal_False;
544 : }
545 : }
546 :
547 0 : void AccessibleTextHelper_Impl::UpdateSelection()
548 : {
549 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
550 :
551 : try
552 : {
553 0 : ESelection aSelection;
554 0 : if( GetEditViewForwarder().GetSelection( aSelection ) )
555 : {
556 0 : if( !maLastSelection.IsEqual( aSelection ) &&
557 0 : aSelection.nEndPara < maParaManager.GetNum() )
558 : {
559 : // #103998# Not that important, changed from assertion to trace
560 0 : if( mbThisHasFocus )
561 : {
562 : OSL_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): Parent has focus!");
563 : }
564 :
565 0 : sal_uInt16 nMaxValidParaIndex( static_cast< sal_uInt16 >( GetTextForwarder().GetParagraphCount() ) - 1 );
566 :
567 : // notify all affected paragraphs (TODO: may be suboptimal,
568 : // since some paragraphs might stay selected)
569 0 : if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND )
570 : {
571 : // Did the caret move from one paragraph to another?
572 : // #100530# no caret events if not focused.
573 0 : if( mbGroupHasFocus &&
574 : maLastSelection.nEndPara != aSelection.nEndPara )
575 : {
576 0 : if( maLastSelection.nEndPara < maParaManager.GetNum() )
577 : {
578 0 : maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ),
579 0 : ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex )+1,
580 : AccessibleEventId::CARET_CHANGED,
581 : uno::makeAny(static_cast<sal_Int32>(-1)),
582 0 : uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) );
583 : }
584 :
585 0 : ChangeChildFocus( aSelection.nEndPara );
586 :
587 : OSL_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): focus changed, Object: %d, Paragraph: %d, Last paragraph: %d",
588 : this, aSelection.nEndPara, maLastSelection.nEndPara);
589 : }
590 : }
591 :
592 : // #100530# no caret events if not focused.
593 0 : if( mbGroupHasFocus )
594 : {
595 0 : uno::Any aOldCursor;
596 :
597 : // #i13705# The old cursor can only contain valid
598 : // values if it's the same paragraph!
599 0 : if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND &&
600 : maLastSelection.nEndPara == aSelection.nEndPara )
601 : {
602 0 : aOldCursor <<= static_cast<sal_Int32>(maLastSelection.nEndPos);
603 : }
604 : else
605 : {
606 0 : aOldCursor <<= static_cast<sal_Int32>(-1);
607 : }
608 :
609 : maParaManager.FireEvent( aSelection.nEndPara,
610 : aSelection.nEndPara+1,
611 : AccessibleEventId::CARET_CHANGED,
612 : uno::makeAny(static_cast<sal_Int32>(aSelection.nEndPos)),
613 0 : aOldCursor );
614 : }
615 :
616 : OSL_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): caret changed, Object: %d, New pos: %d, Old pos: %d, New para: %d, Old para: %d",
617 : this, aSelection.nEndPos, maLastSelection.nEndPos, aSelection.nEndPara, maLastSelection.nEndPara);
618 :
619 : // #108947# Sort new range before calling FireEvent
620 : ::std::pair< xub_StrLen, xub_StrLen > sortedSelection(
621 0 : makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ),
622 0 : ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) );
623 :
624 : // #108947# Sort last range before calling FireEvent
625 : ::std::pair< xub_StrLen, xub_StrLen > sortedLastSelection(
626 0 : makeSortedPair(::std::min( maLastSelection.nStartPara, nMaxValidParaIndex ),
627 0 : ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ) ) );
628 :
629 : // event TEXT_SELECTION_CHANGED has to be submitted. (#i27299#)
630 : const sal_Int16 nTextSelChgEventId =
631 0 : AccessibleEventId::TEXT_SELECTION_CHANGED;
632 : // #107037# notify selection change
633 0 : if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND )
634 : {
635 : // last selection is undefined
636 : // use method <ESelection::HasRange()> (#i27299#)
637 0 : if ( aSelection.HasRange() )
638 : {
639 : // selection was undefined, now is on
640 : maParaManager.FireEvent( sortedSelection.first,
641 : sortedSelection.second+1,
642 0 : nTextSelChgEventId );
643 : }
644 : }
645 : else
646 : {
647 : // last selection is valid
648 : // use method <ESelection::HasRange()> (#i27299#)
649 0 : if ( maLastSelection.HasRange() &&
650 0 : !aSelection.HasRange() )
651 : {
652 : // selection was on, now is empty
653 : maParaManager.FireEvent( sortedLastSelection.first,
654 : sortedLastSelection.second+1,
655 0 : nTextSelChgEventId );
656 : }
657 : // use method <ESelection::HasRange()> (#i27299#)
658 0 : else if( !maLastSelection.HasRange() &&
659 0 : aSelection.HasRange() )
660 : {
661 : // selection was empty, now is on
662 : maParaManager.FireEvent( sortedSelection.first,
663 : sortedSelection.second+1,
664 0 : nTextSelChgEventId );
665 : }
666 : // no event TEXT_SELECTION_CHANGED event, if new and
667 : // last selection are empty. (#i27299#)
668 0 : else if ( maLastSelection.HasRange() &&
669 0 : aSelection.HasRange() )
670 : {
671 : // use sorted last and new selection
672 0 : ESelection aTmpLastSel( maLastSelection );
673 0 : aTmpLastSel.Adjust();
674 0 : ESelection aTmpSel( aSelection );
675 0 : aTmpSel.Adjust();
676 : // first submit event for new and changed selection
677 0 : sal_uInt32 nPara = aTmpSel.nStartPara;
678 0 : for ( ; nPara <= aTmpSel.nEndPara; ++nPara )
679 : {
680 0 : if ( nPara < aTmpLastSel.nStartPara ||
681 : nPara > aTmpLastSel.nEndPara )
682 : {
683 : // new selection on paragraph <nPara>
684 : maParaManager.FireEvent( nPara,
685 0 : nTextSelChgEventId );
686 : }
687 : else
688 : {
689 : // check for changed selection on paragraph <nPara>
690 : const xub_StrLen nParaStartPos =
691 : nPara == aTmpSel.nStartPara
692 0 : ? aTmpSel.nStartPos : 0;
693 : const xub_StrLen nParaEndPos =
694 : nPara == aTmpSel.nEndPara
695 0 : ? aTmpSel.nEndPos : STRING_LEN;
696 : const xub_StrLen nLastParaStartPos =
697 : nPara == aTmpLastSel.nStartPara
698 0 : ? aTmpLastSel.nStartPos : 0;
699 : const xub_StrLen nLastParaEndPos =
700 : nPara == aTmpLastSel.nEndPara
701 0 : ? aTmpLastSel.nEndPos : STRING_LEN;
702 0 : if ( nParaStartPos != nLastParaStartPos ||
703 : nParaEndPos != nLastParaEndPos )
704 : {
705 : maParaManager.FireEvent(
706 0 : nPara, nTextSelChgEventId );
707 : }
708 : }
709 : }
710 : // second submit event for 'old' selections
711 0 : nPara = aTmpLastSel.nStartPara;
712 0 : for ( ; nPara <= aTmpLastSel.nEndPara; ++nPara )
713 : {
714 0 : if ( nPara < aTmpSel.nStartPara ||
715 : nPara > aTmpSel.nEndPara )
716 : {
717 : maParaManager.FireEvent( nPara,
718 0 : nTextSelChgEventId );
719 : }
720 : }
721 : }
722 : }
723 :
724 0 : maLastSelection = aSelection;
725 : }
726 : }
727 : }
728 : // no selection? no update actions
729 0 : catch( const uno::RuntimeException& ) {}
730 0 : }
731 :
732 0 : void AccessibleTextHelper_Impl::ShutdownEditSource() SAL_THROW((uno::RuntimeException))
733 : {
734 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
735 :
736 : // This should only be called with solar mutex locked, i.e. from the main office thread
737 :
738 : // This here is somewhat clumsy: As soon as our children have
739 : // a NULL EditSource (maParaManager.SetEditSource()), they
740 : // enter the disposed state and cannot be reanimated. Thus, it
741 : // is unavoidable and a hard requirement to let go and create
742 : // from scratch each and every child.
743 :
744 : // invalidate children
745 0 : maParaManager.Dispose();
746 0 : maParaManager.SetNum(0);
747 :
748 : // lost all children
749 0 : if( mxFrontEnd.is() )
750 0 : FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
751 :
752 : // quit listen on stale edit source
753 0 : if( maEditSource.IsValid() )
754 0 : EndListening( maEditSource.GetBroadcaster() );
755 :
756 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
757 0 : maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
758 : SAL_WNODEPRECATED_DECLARATIONS_POP
759 0 : }
760 :
761 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
762 0 : void AccessibleTextHelper_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
763 : {
764 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
765 :
766 : // This should only be called with solar mutex locked, i.e. from the main office thread
767 :
768 : // shutdown old edit source
769 0 : ShutdownEditSource();
770 :
771 : // set new edit source
772 0 : maEditSource.SetEditSource( pEditSource );
773 :
774 : // init child vector to the current child count
775 0 : if( maEditSource.IsValid() )
776 : {
777 0 : maParaManager.SetNum( GetTextForwarder().GetParagraphCount() );
778 :
779 : // listen on new edit source
780 0 : StartListening( maEditSource.GetBroadcaster() );
781 :
782 0 : UpdateVisibleChildren();
783 : }
784 0 : }
785 : SAL_WNODEPRECATED_DECLARATIONS_POP
786 :
787 0 : void AccessibleTextHelper_Impl::SetOffset( const Point& rPoint )
788 : {
789 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
790 :
791 : // guard against non-atomic access to maOffset data structure
792 : {
793 0 : ::osl::MutexGuard aGuard( maMutex );
794 0 : maOffset = rPoint;
795 : }
796 :
797 0 : maParaManager.SetEEOffset( rPoint );
798 :
799 : // in all cases, check visibility afterwards.
800 0 : UpdateVisibleChildren();
801 0 : UpdateBoundRect();
802 0 : }
803 :
804 0 : void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents )
805 : {
806 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
807 :
808 : try
809 : {
810 0 : SvxTextForwarder& rCacheTF = GetTextForwarder();
811 0 : SvxViewForwarder& rCacheVF = GetViewForwarder();
812 :
813 0 : Rectangle aViewArea = rCacheVF.GetVisArea();
814 :
815 0 : if( IsActive() )
816 : {
817 : // maybe the edit view scrolls, adapt aViewArea
818 0 : Rectangle aEditViewArea = GetEditViewForwarder().GetVisArea();
819 0 : aViewArea += aEditViewArea.TopLeft();
820 :
821 : // now determine intersection
822 0 : aViewArea.Intersection( aEditViewArea );
823 : }
824 :
825 0 : Rectangle aTmpBB, aParaBB;
826 0 : sal_Bool bFirstChild = sal_True;
827 : sal_Int32 nCurrPara;
828 0 : sal_Int32 nParas=rCacheTF.GetParagraphCount();
829 :
830 0 : mnFirstVisibleChild = -1;
831 0 : mnLastVisibleChild = -2;
832 :
833 0 : for( nCurrPara=0; nCurrPara<nParas; ++nCurrPara )
834 : {
835 : DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX,
836 : "AccessibleTextHelper_Impl::UpdateVisibleChildren: index value overflow");
837 :
838 0 : aTmpBB = rCacheTF.GetParaBounds( static_cast< sal_uInt16 >( nCurrPara ) );
839 :
840 : // convert to screen coordinates
841 0 : aParaBB = ::accessibility::AccessibleEditableTextPara::LogicToPixel( aTmpBB, rCacheTF.GetMapMode(), rCacheVF );
842 :
843 0 : if( aParaBB.IsOver( aViewArea ) )
844 : {
845 : // at least partially visible
846 0 : if( bFirstChild )
847 : {
848 0 : bFirstChild = sal_False;
849 0 : mnFirstVisibleChild = nCurrPara;
850 : }
851 :
852 0 : mnLastVisibleChild = nCurrPara;
853 :
854 : // child not yet created?
855 0 : ::accessibility::AccessibleParaManager::WeakChild aChild( maParaManager.GetChild(nCurrPara) );
856 0 : if( aChild.second.Width == 0 &&
857 : aChild.second.Height == 0 &&
858 0 : mxFrontEnd.is() &&
859 : bBroadcastEvents )
860 : {
861 : GotPropertyEvent( uno::makeAny( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild,
862 0 : mxFrontEnd, GetEditSource(), nCurrPara ).first ),
863 0 : AccessibleEventId::CHILD );
864 0 : }
865 : }
866 : else
867 : {
868 : // not or no longer visible
869 0 : if( maParaManager.IsReferencable( nCurrPara ) )
870 : {
871 0 : if( bBroadcastEvents )
872 0 : LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ),
873 0 : AccessibleEventId::CHILD );
874 :
875 : // clear reference
876 0 : maParaManager.Release( nCurrPara );
877 : }
878 : }
879 : }
880 : }
881 0 : catch( const uno::Exception& )
882 : {
883 : OSL_FAIL("AccessibleTextHelper_Impl::UpdateVisibleChildren error while determining visible children");
884 :
885 : // something failed - currently no children
886 0 : mnFirstVisibleChild = -1;
887 0 : mnLastVisibleChild = -2;
888 0 : maParaManager.SetNum(0);
889 :
890 : // lost all children
891 0 : if( bBroadcastEvents )
892 0 : FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
893 : }
894 0 : }
895 :
896 : // functor for checking changes in paragraph bounding boxes (no stand-alone function, maybe not inlined)
897 : class AccessibleTextHelper_UpdateChildBounds : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&,
898 : ::accessibility::AccessibleParaManager::WeakChild >
899 : {
900 : public:
901 0 : AccessibleTextHelper_UpdateChildBounds( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
902 0 : ::accessibility::AccessibleParaManager::WeakChild operator()( const ::accessibility::AccessibleParaManager::WeakChild& rChild )
903 : {
904 : // retrieve hard reference from weak one
905 0 : ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rChild.first.get() );
906 :
907 0 : if( aHardRef.is() )
908 : {
909 0 : awt::Rectangle aNewRect = aHardRef->getBounds();
910 0 : const awt::Rectangle& aOldRect = rChild.second;
911 :
912 0 : if( aNewRect.X != aOldRect.X ||
913 : aNewRect.Y != aOldRect.Y ||
914 : aNewRect.Width != aOldRect.Width ||
915 : aNewRect.Height != aOldRect.Height )
916 : {
917 : // visible data changed
918 0 : aHardRef->FireEvent( AccessibleEventId::BOUNDRECT_CHANGED );
919 :
920 : // update internal bounds
921 0 : return ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect );
922 : }
923 : }
924 :
925 : // identity transform
926 0 : return rChild;
927 : }
928 :
929 : private:
930 : AccessibleTextHelper_Impl& mrImpl;
931 : };
932 :
933 0 : void AccessibleTextHelper_Impl::UpdateBoundRect()
934 : {
935 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
936 :
937 : // send BOUNDRECT_CHANGED to affected children
938 0 : AccessibleTextHelper_UpdateChildBounds aFunctor( *this );
939 0 : ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor );
940 0 : }
941 :
942 : #ifdef DBG_UTIL
943 : void AccessibleTextHelper_Impl::CheckInvariants() const
944 : {
945 : if( mnFirstVisibleChild >= 0 &&
946 : mnFirstVisibleChild > mnLastVisibleChild )
947 : {
948 : OSL_FAIL( "AccessibleTextHelper: range invalid" );
949 : }
950 : }
951 : #endif
952 :
953 : // functor for sending child events (no stand-alone function, they are maybe not inlined)
954 : class AccessibleTextHelper_LostChildEvent : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&, void >
955 : {
956 : public:
957 0 : AccessibleTextHelper_LostChildEvent( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
958 0 : void operator()( const ::accessibility::AccessibleParaManager::WeakChild& rPara )
959 : {
960 : // retrieve hard reference from weak one
961 0 : ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rPara.first.get() );
962 :
963 0 : if( aHardRef.is() )
964 0 : mrImpl.FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( aHardRef.getRef() ) );
965 0 : }
966 :
967 : private:
968 : AccessibleTextHelper_Impl& mrImpl;
969 : };
970 :
971 0 : void AccessibleTextHelper_Impl::ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast )
972 : {
973 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
974 :
975 0 : const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
976 :
977 : /* rotate paragraphs
978 : * =================
979 : *
980 : * Three cases:
981 : *
982 : * 1.
983 : * ... nParagraph ... nParam1 ... nParam2 ...
984 : * |______________[xxxxxxxxxxx]
985 : * becomes
986 : * [xxxxxxxxxxx]|______________
987 : *
988 : * tail is 0
989 : *
990 : * 2.
991 : * ... nParam1 ... nParagraph ... nParam2 ...
992 : * [xxxxxxxxxxx|xxxxxxxxxxxxxx]____________
993 : * becomes
994 : * ____________[xxxxxxxxxxx|xxxxxxxxxxxxxx]
995 : *
996 : * tail is nParagraph - nParam1
997 : *
998 : * 3.
999 : * ... nParam1 ... nParam2 ... nParagraph ...
1000 : * [xxxxxxxxxxx]___________|____________
1001 : * becomes
1002 : * ___________|____________[xxxxxxxxxxx]
1003 : *
1004 : * tail is nParam2 - nParam1
1005 : */
1006 :
1007 : // sort nParagraph, nParam1 and nParam2 in ascending order, calc range
1008 0 : if( nMiddle < nFirst )
1009 : {
1010 0 : ::std::swap(nFirst, nMiddle);
1011 : }
1012 0 : else if( nMiddle < nLast )
1013 : {
1014 0 : nLast = nLast + nMiddle - nFirst;
1015 : }
1016 : else
1017 : {
1018 0 : ::std::swap(nMiddle, nLast);
1019 0 : nLast = nLast + nMiddle - nFirst;
1020 : }
1021 :
1022 0 : if( nFirst < nParas && nMiddle < nParas && nLast < nParas )
1023 : {
1024 : // since we have no "paragraph index
1025 : // changed" event on UAA, remove
1026 : // [first,last] and insert again later (in
1027 : // UpdateVisibleChildren)
1028 :
1029 : // maParaManager.Rotate( nFirst, nMiddle, nLast );
1030 :
1031 : // send CHILD_EVENT to affected children
1032 0 : ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
1033 0 : ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
1034 :
1035 0 : ::std::advance( begin, nFirst );
1036 0 : ::std::advance( end, nLast+1 );
1037 :
1038 : // TODO: maybe optimize here in the following way. If the
1039 : // number of removed children exceeds a certain threshold,
1040 : // use INVALIDATE_CHILDREN
1041 0 : AccessibleTextHelper_LostChildEvent aFunctor( *this );
1042 :
1043 0 : ::std::for_each( begin, end, aFunctor );
1044 :
1045 0 : maParaManager.Release(nFirst, nLast+1);
1046 : // should be no need for UpdateBoundRect, since all affected children are cleared.
1047 : }
1048 0 : }
1049 :
1050 : // functor for sending child events (no stand-alone function, they are maybe not inlined)
1051 : class AccessibleTextHelper_ChildrenTextChanged : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
1052 : {
1053 : public:
1054 0 : void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
1055 : {
1056 0 : rPara.TextChanged();
1057 0 : }
1058 : };
1059 :
1060 : /** functor processing queue events
1061 :
1062 : Reacts on TEXT_HINT_PARAINSERTED/REMOVED events and stores
1063 : their content
1064 : */
1065 : class AccessibleTextHelper_QueueFunctor : public ::std::unary_function< const SfxHint*, void >
1066 : {
1067 : public:
1068 0 : AccessibleTextHelper_QueueFunctor() :
1069 : mnParasChanged( 0 ),
1070 : mnParaIndex(-1),
1071 0 : mnHintId(-1)
1072 0 : {}
1073 0 : void operator()( const SfxHint* pEvent )
1074 : {
1075 0 : if( pEvent &&
1076 : mnParasChanged != -1 )
1077 : {
1078 : // determine hint type
1079 0 : const TextHint* pTextHint = PTR_CAST( TextHint, pEvent );
1080 0 : const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, pEvent );
1081 :
1082 0 : if( !pEditSourceHint && pTextHint &&
1083 0 : (pTextHint->GetId() == TEXT_HINT_PARAINSERTED ||
1084 0 : pTextHint->GetId() == TEXT_HINT_PARAREMOVED ) )
1085 : {
1086 0 : if( pTextHint->GetValue() == EE_PARA_ALL )
1087 : {
1088 0 : mnParasChanged = -1;
1089 : }
1090 : else
1091 : {
1092 0 : mnHintId = pTextHint->GetId();
1093 0 : mnParaIndex = pTextHint->GetValue();
1094 0 : ++mnParasChanged;
1095 : }
1096 : }
1097 : }
1098 0 : }
1099 :
1100 : /** Query number of paragraphs changed during queue processing.
1101 :
1102 : @return number of changed paragraphs, -1 for
1103 : "every paragraph changed"
1104 : */
1105 0 : int GetNumberOfParasChanged() { return mnParasChanged; }
1106 : /** Query index of last added/removed paragraph
1107 :
1108 : @return index of lastly added paragraphs, -1 for none
1109 : added so far.
1110 : */
1111 0 : int GetParaIndex() { return mnParaIndex; }
1112 : /** Query hint id of last interesting event
1113 :
1114 : @return hint id of last interesting event (REMOVED/INSERTED).
1115 : */
1116 0 : int GetHintId() { return mnHintId; }
1117 :
1118 : private:
1119 : /** number of paragraphs changed during queue processing. -1 for
1120 : "every paragraph changed"
1121 : */
1122 : int mnParasChanged;
1123 : /// index of paragraph added/removed last
1124 : int mnParaIndex;
1125 : /// TextHint ID (removed/inserted) of last interesting event
1126 : int mnHintId;
1127 : };
1128 :
1129 0 : void AccessibleTextHelper_Impl::ProcessQueue()
1130 : {
1131 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1132 :
1133 : // inspect queue for paragraph insert/remove events. If there
1134 : // is exactly _one_ of those in the queue, and the number of
1135 : // paragraphs has changed by exactly one, use that event to
1136 : // determine a priori which paragraph was added/removed. This
1137 : // is necessary, since I must sync right here with the
1138 : // EditEngine state (number of paragraphs etc.), since I'm
1139 : // potentially sending listener events right away.
1140 0 : AccessibleTextHelper_QueueFunctor aFunctor;
1141 0 : maEventQueue.ForEach( aFunctor );
1142 :
1143 0 : const sal_Int32 nNewParas( GetTextForwarder().GetParagraphCount() );
1144 0 : const sal_Int32 nCurrParas( maParaManager.GetNum() );
1145 :
1146 : // whether every paragraph already is updated (no need to
1147 : // repeat that later on, e.g. for PARA_MOVED events)
1148 0 : bool bEverythingUpdated( false );
1149 :
1150 0 : if( labs( nNewParas - nCurrParas ) == 1 &&
1151 0 : aFunctor.GetNumberOfParasChanged() == 1 )
1152 : {
1153 : // #103483# Exactly one paragraph added/removed. This is
1154 : // the normal case, optimize event handling here.
1155 :
1156 0 : if( aFunctor.GetHintId() == TEXT_HINT_PARAINSERTED )
1157 : {
1158 : // update num of paras
1159 0 : maParaManager.SetNum( nNewParas );
1160 :
1161 : // release everything from the insertion position until the end
1162 0 : maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
1163 :
1164 : // TODO: Clarify whether this behaviour _really_ saves
1165 : // anybody anything!
1166 : // update children, _don't_ broadcast
1167 0 : UpdateVisibleChildren( false );
1168 0 : UpdateBoundRect();
1169 :
1170 : // send insert event
1171 : // #109864# Enforce creation of this paragraph
1172 : try
1173 : {
1174 0 : GotPropertyEvent( uno::makeAny( getAccessibleChild( aFunctor.GetParaIndex() -
1175 0 : mnFirstVisibleChild + GetStartIndex() ) ),
1176 0 : AccessibleEventId::CHILD );
1177 : }
1178 0 : catch( const uno::Exception& )
1179 : {
1180 : OSL_FAIL("AccessibleTextHelper_Impl::ProcessQueue: could not create new paragraph");
1181 : }
1182 : }
1183 0 : else if( aFunctor.GetHintId() == TEXT_HINT_PARAREMOVED )
1184 : {
1185 0 : ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
1186 0 : ::std::advance( begin, aFunctor.GetParaIndex() );
1187 0 : ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
1188 0 : ::std::advance( end, 1 );
1189 :
1190 : // #i61812# remember para to be removed for later notification
1191 : // AFTER the new state is applied (that after the para got removed)
1192 0 : ::uno::Reference< XAccessible > xPara;
1193 0 : ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( begin->first.get() );
1194 0 : if( aHardRef.is() )
1195 0 : xPara = ::uno::Reference< XAccessible >( aHardRef.getRef(), ::uno::UNO_QUERY );
1196 :
1197 : // release everything from the remove position until the end
1198 0 : maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
1199 :
1200 : // update num of paras
1201 0 : maParaManager.SetNum( nNewParas );
1202 :
1203 : // TODO: Clarify whether this behaviour _really_ saves
1204 : // anybody anything!
1205 : // update children, _don't_ broadcast
1206 0 : UpdateVisibleChildren( false );
1207 0 : UpdateBoundRect();
1208 :
1209 : // #i61812# notification for removed para
1210 0 : if (xPara.is())
1211 0 : FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( xPara) );
1212 : }
1213 : #ifdef DBG_UTIL
1214 : else
1215 : OSL_FAIL("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id");
1216 : #endif
1217 : }
1218 0 : else if( nNewParas != nCurrParas )
1219 : {
1220 : // release all paras
1221 0 : maParaManager.Release(0, nCurrParas);
1222 :
1223 : // update num of paras
1224 0 : maParaManager.SetNum( nNewParas );
1225 :
1226 : // #109864# create from scratch, don't broadcast
1227 0 : UpdateVisibleChildren( false );
1228 0 : UpdateBoundRect();
1229 :
1230 : // number of paragraphs somehow changed - but we have no
1231 : // chance determining how. Thus, throw away everything and
1232 : // create from scratch.
1233 : // (child events should be broadcast after the changes are done...)
1234 0 : FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
1235 :
1236 : // no need for further updates later on
1237 0 : bEverythingUpdated = true;
1238 : }
1239 :
1240 0 : while( !maEventQueue.IsEmpty() )
1241 : {
1242 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1243 0 : ::std::auto_ptr< SfxHint > pHint( maEventQueue.PopFront() );
1244 : SAL_WNODEPRECATED_DECLARATIONS_POP
1245 0 : if( pHint.get() )
1246 : {
1247 0 : const SfxHint& rHint = *(pHint.get());
1248 :
1249 : // determine hint type
1250 0 : const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
1251 0 : const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
1252 0 : const TextHint* pTextHint = PTR_CAST( TextHint, &rHint );
1253 0 : const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint );
1254 0 : const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint );
1255 :
1256 : try
1257 : {
1258 0 : const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
1259 :
1260 0 : if( pEditSourceHint )
1261 : {
1262 0 : switch( pEditSourceHint->GetId() )
1263 : {
1264 : case EDITSOURCE_HINT_PARASMOVED:
1265 : {
1266 : DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() &&
1267 : pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(),
1268 : "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification");
1269 :
1270 0 : if( !bEverythingUpdated )
1271 : {
1272 0 : ParagraphsMoved(pEditSourceHint->GetStartValue(),
1273 0 : pEditSourceHint->GetValue(),
1274 0 : pEditSourceHint->GetEndValue());
1275 :
1276 : // in all cases, check visibility afterwards.
1277 0 : UpdateVisibleChildren();
1278 : }
1279 0 : break;
1280 : }
1281 :
1282 : case EDITSOURCE_HINT_SELECTIONCHANGED:
1283 : // notify listeners
1284 : try
1285 : {
1286 0 : UpdateSelection();
1287 : }
1288 : // maybe we're not in edit mode (this is not an error)
1289 0 : catch( const uno::Exception& ) {}
1290 0 : break;
1291 : }
1292 : }
1293 0 : else if( pTextHint )
1294 : {
1295 0 : switch( pTextHint->GetId() )
1296 : {
1297 : case TEXT_HINT_MODIFIED:
1298 : {
1299 : // notify listeners
1300 0 : sal_Int32 nPara( pTextHint->GetValue() );
1301 :
1302 : // #108900# Delegate change event to children
1303 : AccessibleTextHelper_ChildrenTextChanged aNotifyChildrenFunctor;
1304 :
1305 0 : if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) )
1306 : {
1307 : // #108900# Call every child
1308 : ::std::for_each( maParaManager.begin(), maParaManager.end(),
1309 0 : AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
1310 : }
1311 : else
1312 0 : if( nPara < nParas )
1313 : {
1314 : // #108900# Call child at index nPara
1315 0 : ::std::for_each( maParaManager.begin()+nPara, maParaManager.begin()+nPara+1,
1316 0 : AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
1317 : }
1318 : break;
1319 : }
1320 :
1321 : case TEXT_HINT_PARAINSERTED:
1322 : // already happened above
1323 0 : break;
1324 :
1325 : case TEXT_HINT_PARAREMOVED:
1326 : // already happened above
1327 0 : break;
1328 :
1329 : case TEXT_HINT_TEXTHEIGHTCHANGED:
1330 : // visibility changed, done below
1331 0 : break;
1332 :
1333 : case TEXT_HINT_VIEWSCROLLED:
1334 : // visibility changed, done below
1335 0 : break;
1336 : }
1337 :
1338 : // in all cases, check visibility afterwards.
1339 0 : UpdateVisibleChildren();
1340 0 : UpdateBoundRect();
1341 : }
1342 0 : else if( pViewHint )
1343 : {
1344 0 : switch( pViewHint->GetHintType() )
1345 : {
1346 : case SvxViewHint::SVX_HINT_VIEWCHANGED:
1347 : // just check visibility
1348 0 : UpdateVisibleChildren();
1349 0 : UpdateBoundRect();
1350 0 : break;
1351 : }
1352 : }
1353 0 : else if( pSdrHint )
1354 : {
1355 0 : switch( pSdrHint->GetKind() )
1356 : {
1357 : case HINT_BEGEDIT:
1358 : {
1359 : // change children state
1360 0 : maParaManager.SetActive();
1361 :
1362 : // per definition, edit mode text has the focus
1363 0 : SetFocus( sal_True );
1364 0 : break;
1365 : }
1366 :
1367 : case HINT_ENDEDIT:
1368 : {
1369 : // focused child now looses focus
1370 0 : ESelection aSelection;
1371 0 : if( GetEditViewForwarder().GetSelection( aSelection ) )
1372 0 : SetChildFocus( aSelection.nEndPara, sal_False );
1373 :
1374 : // change children state
1375 0 : maParaManager.SetActive( sal_False );
1376 :
1377 : maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND,
1378 0 : EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND);
1379 : break;
1380 : }
1381 : default:
1382 0 : break;
1383 : }
1384 : }
1385 : // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
1386 0 : else if( pSimpleHint )
1387 : {
1388 0 : switch( pSimpleHint->GetId() )
1389 : {
1390 : case SFX_HINT_DYING:
1391 : // edit source is dying under us, become defunc then
1392 : try
1393 : {
1394 : // make edit source inaccessible
1395 : // Note: cannot destroy it here, since we're called from there!
1396 0 : ShutdownEditSource();
1397 : }
1398 0 : catch( const uno::Exception& ) {}
1399 :
1400 0 : break;
1401 : }
1402 : }
1403 : }
1404 0 : catch( const uno::Exception& )
1405 : {
1406 : #ifdef DBG_UTIL
1407 : OSL_TRACE("AccessibleTextHelper_Impl::ProcessQueue: Unhandled exception.");
1408 : #endif
1409 : }
1410 : }
1411 0 : }
1412 0 : }
1413 :
1414 0 : void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1415 : {
1416 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1417 :
1418 : // precondition: solar mutex locked
1419 : DBG_TESTSOLARMUTEX();
1420 :
1421 : // precondition: not in a recursion
1422 0 : if( mbInNotify )
1423 0 : return;
1424 :
1425 0 : mbInNotify = sal_True;
1426 :
1427 : // determine hint type
1428 0 : const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
1429 0 : const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
1430 0 : const TextHint* pTextHint = PTR_CAST( TextHint, &rHint );
1431 0 : const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint );
1432 0 : const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint );
1433 :
1434 : try
1435 : {
1436 : // Process notification event
1437 0 : if( pEditSourceHint )
1438 : {
1439 0 : maEventQueue.Append( *pEditSourceHint );
1440 : // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#)
1441 0 : if( maEventOpenFrames == 0 )
1442 0 : ProcessQueue();
1443 : }
1444 0 : else if( pTextHint )
1445 : {
1446 0 : switch( pTextHint->GetId() )
1447 : {
1448 : case TEXT_HINT_BLOCKNOTIFICATION_END:
1449 : case TEXT_HINT_INPUT_END:
1450 0 : --maEventOpenFrames;
1451 :
1452 0 : if( maEventOpenFrames == 0 )
1453 : {
1454 : // #103483#
1455 : /* All information should have arrived
1456 : * now, process queue. As stated in the
1457 : * above bug, we can often avoid throwing
1458 : * away all paragraphs by looking forward
1459 : * in the event queue (searching for
1460 : * PARAINSERT/REMOVE events). Furthermore,
1461 : * processing the event queue only at the
1462 : * end of an interaction cycle, ensures
1463 : * that the EditEngine state and the
1464 : * AccessibleText state are the same
1465 : * (well, mostly. If there are _multiple_
1466 : * interaction cycles in the EE queues, it
1467 : * can still happen that EE state is
1468 : * different. That's so to say broken by
1469 : * design with that delayed EE event
1470 : * concept).
1471 : */
1472 0 : ProcessQueue();
1473 : }
1474 0 : break;
1475 :
1476 : case TEXT_HINT_BLOCKNOTIFICATION_START:
1477 : case TEXT_HINT_INPUT_START:
1478 0 : ++maEventOpenFrames;
1479 : // no FALLTHROUGH reason: event will not be processed,
1480 : // thus appending the event isn't necessary. (#i27299#)
1481 0 : break;
1482 : default:
1483 0 : maEventQueue.Append( *pTextHint );
1484 : // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#)
1485 0 : if( maEventOpenFrames == 0 )
1486 0 : ProcessQueue();
1487 0 : break;
1488 : }
1489 : }
1490 0 : else if( pViewHint )
1491 : {
1492 0 : maEventQueue.Append( *pViewHint );
1493 :
1494 : // process visibility right away, if not within an
1495 : // open EE notification frame. Otherwise, event
1496 : // processing would be delayed until next EE
1497 : // notification sequence.
1498 0 : if( maEventOpenFrames == 0 )
1499 0 : ProcessQueue();
1500 : }
1501 0 : else if( pSdrHint )
1502 : {
1503 0 : maEventQueue.Append( *pSdrHint );
1504 :
1505 : // process drawing layer events right away, if not
1506 : // within an open EE notification frame. Otherwise,
1507 : // event processing would be delayed until next EE
1508 : // notification sequence.
1509 0 : if( maEventOpenFrames == 0 )
1510 0 : ProcessQueue();
1511 : }
1512 : // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
1513 0 : else if( pSimpleHint )
1514 : {
1515 : // handle this event _at once_, because after that, objects are invalid
1516 0 : switch( pSimpleHint->GetId() )
1517 : {
1518 : case SFX_HINT_DYING:
1519 : // edit source is dying under us, become defunc then
1520 0 : maEventQueue.Clear();
1521 : try
1522 : {
1523 : // make edit source inaccessible
1524 : // Note: cannot destroy it here, since we're called from there!
1525 0 : ShutdownEditSource();
1526 : }
1527 0 : catch( const uno::Exception& ) {}
1528 :
1529 0 : break;
1530 : }
1531 : }
1532 : }
1533 0 : catch( const uno::Exception& )
1534 : {
1535 : #ifdef DBG_UTIL
1536 : OSL_TRACE("AccessibleTextHelper_Impl::Notify: Unhandled exception.");
1537 : #endif
1538 0 : mbInNotify = sal_False;
1539 : }
1540 :
1541 0 : mbInNotify = sal_False;
1542 : }
1543 :
1544 0 : void AccessibleTextHelper_Impl::Dispose()
1545 : {
1546 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1547 :
1548 0 : if( getNotifierClientId() != -1 )
1549 : {
1550 : try
1551 : {
1552 : // #106234# Unregister from EventNotifier
1553 0 : ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() );
1554 : #ifdef DBG_UTIL
1555 : OSL_TRACE( "AccessibleTextHelper_Impl disposed ID: %d", mnNotifierClientId );
1556 : #endif
1557 : }
1558 0 : catch( const uno::Exception& ) {}
1559 :
1560 0 : mnNotifierClientId = -1;
1561 : }
1562 :
1563 : try
1564 : {
1565 : // dispose children
1566 0 : maParaManager.Dispose();
1567 : }
1568 0 : catch( const uno::Exception& ) {}
1569 :
1570 : // quit listen on stale edit source
1571 0 : if( maEditSource.IsValid() )
1572 0 : EndListening( maEditSource.GetBroadcaster() );
1573 :
1574 : // clear references
1575 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1576 0 : maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) );
1577 : SAL_WNODEPRECATED_DECLARATIONS_POP
1578 0 : mxFrontEnd = NULL;
1579 0 : }
1580 :
1581 0 : void AccessibleTextHelper_Impl::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
1582 : {
1583 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1584 :
1585 : // -- object locked --
1586 0 : ::osl::ClearableMutexGuard aGuard( maMutex );
1587 :
1588 0 : AccessibleEventObject aEvent;
1589 :
1590 : DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper::FireEvent: no event source set" );
1591 :
1592 0 : if( mxFrontEnd.is() )
1593 0 : aEvent = AccessibleEventObject(mxFrontEnd->getAccessibleContext(), nEventId, rNewValue, rOldValue);
1594 : else
1595 0 : aEvent = AccessibleEventObject(uno::Reference< uno::XInterface >(), nEventId, rNewValue, rOldValue);
1596 :
1597 : // no locking necessary, FireEvent internally copies listeners
1598 : // if someone removes/adds in between Further locking,
1599 : // actually, might lead to deadlocks, since we're calling out
1600 : // of this object
1601 0 : aGuard.clear();
1602 : // -- until here --
1603 :
1604 0 : FireEvent(aEvent);
1605 0 : }
1606 :
1607 0 : void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const
1608 : {
1609 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1610 :
1611 : // #102261# Call global queue for focus events
1612 0 : if( rEvent.EventId == AccessibleStateType::FOCUSED )
1613 0 : vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent );
1614 :
1615 : // #106234# Delegate to EventNotifier
1616 0 : ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(),
1617 0 : rEvent );
1618 0 : }
1619 :
1620 : // XAccessibleContext
1621 0 : sal_Int32 SAL_CALL AccessibleTextHelper_Impl::getAccessibleChildCount() SAL_THROW((uno::RuntimeException))
1622 : {
1623 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1624 :
1625 0 : return mnLastVisibleChild - mnFirstVisibleChild + 1;
1626 : }
1627 :
1628 0 : uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
1629 : {
1630 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1631 :
1632 0 : i -= GetStartIndex();
1633 :
1634 0 : if( 0 > i || i >= getAccessibleChildCount() ||
1635 0 : GetTextForwarder().GetParagraphCount() <= i )
1636 : {
1637 0 : throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid child index")), mxFrontEnd);
1638 : }
1639 :
1640 : DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper_Impl::UpdateVisibleChildren: no frontend set");
1641 :
1642 0 : if( mxFrontEnd.is() )
1643 0 : return maParaManager.CreateChild( i, mxFrontEnd, GetEditSource(), mnFirstVisibleChild + i ).first;
1644 : else
1645 0 : return NULL;
1646 : }
1647 :
1648 0 : void SAL_CALL AccessibleTextHelper_Impl::addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
1649 : {
1650 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1651 :
1652 0 : if( getNotifierClientId() != -1 )
1653 0 : ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener );
1654 0 : }
1655 :
1656 0 : void SAL_CALL AccessibleTextHelper_Impl::removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
1657 : {
1658 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1659 :
1660 0 : if( getNotifierClientId() != -1 )
1661 0 : ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener );
1662 0 : }
1663 :
1664 0 : uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleAtPoint( const awt::Point& _aPoint ) SAL_THROW((uno::RuntimeException))
1665 : {
1666 : DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL );
1667 :
1668 : // make given position relative
1669 0 : if( !mxFrontEnd.is() )
1670 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
1671 :
1672 0 : uno::Reference< XAccessibleContext > xFrontEndContext = mxFrontEnd->getAccessibleContext();
1673 :
1674 0 : if( !xFrontEndContext.is() )
1675 0 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd );
1676 :
1677 0 : uno::Reference< XAccessibleComponent > xFrontEndComponent( xFrontEndContext, uno::UNO_QUERY );
1678 :
1679 0 : if( !xFrontEndComponent.is() )
1680 : throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend is no XAccessibleComponent")),
1681 0 : mxFrontEnd );
1682 :
1683 : // #103862# No longer need to make given position relative
1684 0 : Point aPoint( _aPoint.X, _aPoint.Y );
1685 :
1686 : // respect EditEngine offset to surrounding shape/cell
1687 0 : aPoint -= GetOffset();
1688 :
1689 : // convert to EditEngine coordinate system
1690 0 : SvxTextForwarder& rCacheTF = GetTextForwarder();
1691 0 : Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
1692 :
1693 : // iterate over all visible children (including those not yet created)
1694 : sal_Int32 nChild;
1695 0 : for( nChild=mnFirstVisibleChild; nChild <= mnLastVisibleChild; ++nChild )
1696 : {
1697 : DBG_ASSERT(nChild >= 0 && nChild <= USHRT_MAX,
1698 : "AccessibleTextHelper_Impl::getAccessibleAt: index value overflow");
1699 :
1700 0 : Rectangle aParaBounds( rCacheTF.GetParaBounds( static_cast< sal_uInt16 > (nChild) ) );
1701 :
1702 0 : if( aParaBounds.IsInside( aLogPoint ) )
1703 0 : return getAccessibleChild( nChild - mnFirstVisibleChild + GetStartIndex() );
1704 : }
1705 :
1706 : // found none
1707 0 : return NULL;
1708 : }
1709 :
1710 : //------------------------------------------------------------------------
1711 : //
1712 : // AccessibleTextHelper implementation (simply forwards to impl)
1713 : //
1714 : //------------------------------------------------------------------------
1715 :
1716 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1717 0 : AccessibleTextHelper::AccessibleTextHelper( ::std::auto_ptr< SvxEditSource > pEditSource ) :
1718 0 : mpImpl( new AccessibleTextHelper_Impl() )
1719 : {
1720 0 : SolarMutexGuard aGuard;
1721 :
1722 0 : SetEditSource( pEditSource );
1723 0 : }
1724 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1725 :
1726 0 : AccessibleTextHelper::~AccessibleTextHelper()
1727 : {
1728 0 : }
1729 :
1730 0 : const SvxEditSource& AccessibleTextHelper::GetEditSource() const SAL_THROW((uno::RuntimeException))
1731 : {
1732 : #ifdef DBG_UTIL
1733 : mpImpl->CheckInvariants();
1734 :
1735 : const SvxEditSource& aEditSource = mpImpl->GetEditSource();
1736 :
1737 : mpImpl->CheckInvariants();
1738 :
1739 : return aEditSource;
1740 : #else
1741 0 : return mpImpl->GetEditSource();
1742 : #endif
1743 : }
1744 :
1745 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1746 0 : void AccessibleTextHelper::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException))
1747 : {
1748 : #ifdef DBG_UTIL
1749 : // precondition: solar mutex locked
1750 : DBG_TESTSOLARMUTEX();
1751 :
1752 : mpImpl->CheckInvariants();
1753 : #endif
1754 :
1755 0 : mpImpl->SetEditSource( pEditSource );
1756 :
1757 : #ifdef DBG_UTIL
1758 : mpImpl->CheckInvariants();
1759 : #endif
1760 0 : }
1761 : SAL_WNODEPRECATED_DECLARATIONS_POP
1762 :
1763 0 : void AccessibleTextHelper::SetEventSource( const uno::Reference< XAccessible >& rInterface )
1764 : {
1765 : #ifdef DBG_UTIL
1766 : mpImpl->CheckInvariants();
1767 : #endif
1768 :
1769 0 : mpImpl->SetEventSource( rInterface );
1770 :
1771 : #ifdef DBG_UTIL
1772 : mpImpl->CheckInvariants();
1773 : #endif
1774 0 : }
1775 :
1776 0 : uno::Reference< XAccessible > AccessibleTextHelper::GetEventSource() const
1777 : {
1778 : #ifdef DBG_UTIL
1779 : mpImpl->CheckInvariants();
1780 :
1781 : uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() );
1782 :
1783 : mpImpl->CheckInvariants();
1784 :
1785 : return xRet;
1786 : #else
1787 0 : return mpImpl->GetEventSource();
1788 : #endif
1789 : }
1790 :
1791 0 : void AccessibleTextHelper::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException))
1792 : {
1793 : #ifdef DBG_UTIL
1794 : // precondition: solar mutex locked
1795 : DBG_TESTSOLARMUTEX();
1796 :
1797 : mpImpl->CheckInvariants();
1798 : #endif
1799 :
1800 0 : mpImpl->SetFocus( bHaveFocus );
1801 :
1802 : #ifdef DBG_UTIL
1803 : mpImpl->CheckInvariants();
1804 : #endif
1805 0 : }
1806 :
1807 0 : sal_Bool AccessibleTextHelper::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException))
1808 : {
1809 : #ifdef DBG_UTIL
1810 : mpImpl->CheckInvariants();
1811 :
1812 : sal_Bool bRet( mpImpl->HaveFocus() );
1813 :
1814 : mpImpl->CheckInvariants();
1815 :
1816 : return bRet;
1817 : #else
1818 0 : return mpImpl->HaveFocus();
1819 : #endif
1820 : }
1821 :
1822 0 : void AccessibleTextHelper::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
1823 : {
1824 : #ifdef DBG_UTIL
1825 : mpImpl->CheckInvariants();
1826 : #endif
1827 :
1828 0 : mpImpl->FireEvent( nEventId, rNewValue, rOldValue );
1829 :
1830 : #ifdef DBG_UTIL
1831 : mpImpl->CheckInvariants();
1832 : #endif
1833 0 : }
1834 :
1835 0 : void AccessibleTextHelper::FireEvent( const AccessibleEventObject& rEvent ) const
1836 : {
1837 : #ifdef DBG_UTIL
1838 : mpImpl->CheckInvariants();
1839 : #endif
1840 :
1841 0 : mpImpl->FireEvent( rEvent );
1842 :
1843 : #ifdef DBG_UTIL
1844 : mpImpl->CheckInvariants();
1845 : #endif
1846 0 : }
1847 :
1848 0 : void AccessibleTextHelper::SetOffset( const Point& rPoint )
1849 : {
1850 : #ifdef DBG_UTIL
1851 : // precondition: solar mutex locked
1852 : DBG_TESTSOLARMUTEX();
1853 :
1854 : mpImpl->CheckInvariants();
1855 : #endif
1856 :
1857 0 : mpImpl->SetOffset( rPoint );
1858 :
1859 : #ifdef DBG_UTIL
1860 : mpImpl->CheckInvariants();
1861 : #endif
1862 0 : }
1863 :
1864 0 : Point AccessibleTextHelper::GetOffset() const
1865 : {
1866 : #ifdef DBG_UTIL
1867 : mpImpl->CheckInvariants();
1868 :
1869 : Point aPoint( mpImpl->GetOffset() );
1870 :
1871 : mpImpl->CheckInvariants();
1872 :
1873 : return aPoint;
1874 : #else
1875 0 : return mpImpl->GetOffset();
1876 : #endif
1877 : }
1878 :
1879 0 : void AccessibleTextHelper::SetStartIndex( sal_Int32 nOffset )
1880 : {
1881 : #ifdef DBG_UTIL
1882 : // precondition: solar mutex locked
1883 : DBG_TESTSOLARMUTEX();
1884 :
1885 : mpImpl->CheckInvariants();
1886 : #endif
1887 :
1888 0 : mpImpl->SetStartIndex( nOffset );
1889 :
1890 : #ifdef DBG_UTIL
1891 : mpImpl->CheckInvariants();
1892 : #endif
1893 0 : }
1894 :
1895 0 : sal_Int32 AccessibleTextHelper::GetStartIndex() const
1896 : {
1897 : #ifdef DBG_UTIL
1898 : mpImpl->CheckInvariants();
1899 :
1900 : sal_Int32 nOffset = mpImpl->GetStartIndex();
1901 :
1902 : mpImpl->CheckInvariants();
1903 :
1904 : return nOffset;
1905 : #else
1906 0 : return mpImpl->GetStartIndex();
1907 : #endif
1908 : }
1909 :
1910 0 : void AccessibleTextHelper::SetAdditionalChildStates( const VectorOfStates& rChildStates )
1911 : {
1912 0 : mpImpl->SetAdditionalChildStates( rChildStates );
1913 0 : }
1914 :
1915 0 : void AccessibleTextHelper::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException))
1916 : {
1917 : #ifdef DBG_UTIL
1918 : // precondition: solar mutex locked
1919 : DBG_TESTSOLARMUTEX();
1920 :
1921 : mpImpl->CheckInvariants();
1922 : #endif
1923 :
1924 0 : mpImpl->UpdateVisibleChildren();
1925 0 : mpImpl->UpdateBoundRect();
1926 :
1927 0 : mpImpl->UpdateSelection();
1928 :
1929 : #ifdef DBG_UTIL
1930 : mpImpl->CheckInvariants();
1931 : #endif
1932 0 : }
1933 :
1934 0 : void AccessibleTextHelper::Dispose()
1935 : {
1936 : // As Dispose calls ShutdownEditSource, which in turn
1937 : // deregisters as listener on the edit source, have to lock
1938 : // here
1939 0 : SolarMutexGuard aGuard;
1940 :
1941 : #ifdef DBG_UTIL
1942 : mpImpl->CheckInvariants();
1943 : #endif
1944 :
1945 0 : mpImpl->Dispose();
1946 :
1947 : #ifdef DBG_UTIL
1948 : mpImpl->CheckInvariants();
1949 : #endif
1950 0 : }
1951 :
1952 0 : sal_Bool AccessibleTextHelper::IsSelected() const
1953 : {
1954 0 : SolarMutexGuard aGuard;
1955 :
1956 : #ifdef DBG_UTIL
1957 : mpImpl->CheckInvariants();
1958 :
1959 : sal_Bool aRet = mpImpl->IsSelected();
1960 :
1961 : mpImpl->CheckInvariants();
1962 :
1963 : return aRet;
1964 : #else
1965 0 : return mpImpl->IsSelected();
1966 : #endif
1967 : }
1968 :
1969 : // XAccessibleContext
1970 0 : sal_Int32 AccessibleTextHelper::GetChildCount() SAL_THROW((uno::RuntimeException))
1971 : {
1972 0 : SolarMutexGuard aGuard;
1973 :
1974 : #ifdef DBG_UTIL
1975 : mpImpl->CheckInvariants();
1976 :
1977 : sal_Int32 nRet = mpImpl->getAccessibleChildCount();
1978 :
1979 : mpImpl->CheckInvariants();
1980 :
1981 : return nRet;
1982 : #else
1983 0 : return mpImpl->getAccessibleChildCount();
1984 : #endif
1985 : }
1986 :
1987 0 : uno::Reference< XAccessible > AccessibleTextHelper::GetChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException))
1988 : {
1989 0 : SolarMutexGuard aGuard;
1990 :
1991 : #ifdef DBG_UTIL
1992 : mpImpl->CheckInvariants();
1993 :
1994 : uno::Reference< XAccessible > xRet = mpImpl->getAccessibleChild( i );
1995 :
1996 : mpImpl->CheckInvariants();
1997 :
1998 : return xRet;
1999 : #else
2000 0 : return mpImpl->getAccessibleChild( i );
2001 : #endif
2002 : }
2003 :
2004 0 : void AccessibleTextHelper::AddEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
2005 : {
2006 : #ifdef DBG_UTIL
2007 : mpImpl->CheckInvariants();
2008 :
2009 : mpImpl->addAccessibleEventListener( xListener );
2010 :
2011 : mpImpl->CheckInvariants();
2012 : #else
2013 0 : mpImpl->addAccessibleEventListener( xListener );
2014 : #endif
2015 0 : }
2016 :
2017 0 : void AccessibleTextHelper::RemoveEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException))
2018 : {
2019 : #ifdef DBG_UTIL
2020 : mpImpl->CheckInvariants();
2021 :
2022 : mpImpl->removeAccessibleEventListener( xListener );
2023 :
2024 : mpImpl->CheckInvariants();
2025 : #else
2026 0 : mpImpl->removeAccessibleEventListener( xListener );
2027 : #endif
2028 0 : }
2029 :
2030 : // XAccessibleComponent
2031 0 : uno::Reference< XAccessible > AccessibleTextHelper::GetAt( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException))
2032 : {
2033 0 : SolarMutexGuard aGuard;
2034 :
2035 : #ifdef DBG_UTIL
2036 : mpImpl->CheckInvariants();
2037 :
2038 : uno::Reference< XAccessible > xChild = mpImpl->getAccessibleAtPoint( aPoint );
2039 :
2040 : mpImpl->CheckInvariants();
2041 :
2042 : return xChild;
2043 : #else
2044 0 : return mpImpl->getAccessibleAtPoint( aPoint );
2045 : #endif
2046 : }
2047 :
2048 : } // end of namespace accessibility
2049 :
2050 : //------------------------------------------------------------------------
2051 :
2052 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|