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

Generated by: LCOV version 1.10