LCOV - code coverage report
Current view: top level - svx/source/accessibility - AccessibleTextHelper.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 353 589 59.9 %
Date: 2015-06-13 12:38:46 Functions: 54 72 75.0 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.11