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