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