Files
libreoffice/sw/source/core/access/accmap.cxx
2002-08-15 10:57:22 +00:00

2382 lines
77 KiB
C++

/*************************************************************************
*
* $RCSfile: accmap.cxx,v $
*
* $Revision: 1.35 $
*
* last change: $Author: mib $ $Date: 2002-08-15 11:57:22 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#ifdef PRECOMPILED
#include "core_pch.hxx"
#endif
#pragma hdrstop
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif
#ifndef _CPPUHELPER_WEAKREF_HXX_
#include <cppuhelper/weakref.hxx>
#endif
#ifndef _SV_WINDOW_HXX
#include <vcl/window.hxx>
#endif
#ifndef _SVDMODEL_HXX
#include <svx/svdmodel.hxx>
#endif
#ifndef SVX_UNOMOD_HXX
#include <svx/unomod.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#include <map>
#include <list>
#ifndef _ACCMAP_HXX
#include <accmap.hxx>
#endif
#ifndef _ACCCONTEXT_HXX
#include <acccontext.hxx>
#endif
#ifndef _ACCDOC_HXX
#include <accdoc.hxx>
#endif
#ifndef _ACCPREVIEW_HXX
#include <accpreview.hxx>
#endif
#ifndef _ACCPAGE_HXX
#include <accpage.hxx>
#endif
#ifndef _ACCPARA_HXX
#include <accpara.hxx>
#endif
#ifndef _ACCHEADERFOOTER_HXX
#include <accheaderfooter.hxx>
#endif
#ifndef _ACCFOOTNOTE_HXX
#include <accfootnote.hxx>
#endif
#ifndef _ACCTEXTFRAME_HXX
#include <acctextframe.hxx>
#endif
#ifndef _ACCGRAPHIC_HXX
#include <accgraphic.hxx>
#endif
#ifndef _ACCEMBEDDED_HXX
#include <accembedded.hxx>
#endif
#ifndef _ACCCELL_HXX
#include <acccell.hxx>
#endif
#ifndef _ACCTABLE_HXX
#include <acctable.hxx>
#endif
#ifndef _FESH_HXX
#include "fesh.hxx"
#endif
#ifndef _ROOTFRM_HXX
#include <rootfrm.hxx>
#endif
#ifndef _TXTFRM_HXX
#include <txtfrm.hxx>
#endif
#ifndef _HFFRM_HXX
#include <hffrm.hxx>
#endif
#ifndef _FTNFRM_HXX
#include <ftnfrm.hxx>
#endif
#ifndef _CELLFRM_HXX
#include <cellfrm.hxx>
#endif
#ifndef _TABFRM_HXX
#include <tabfrm.hxx>
#endif
#ifndef _PAGEFRM_HXX
#include <pagefrm.hxx>
#endif
#ifndef _NDTYP_HXX
#include <ndtyp.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _SVX_ACCESSIBILITY_SHAPE_TYPE_HANDLER_HXX
#include <svx/ShapeTypeHandler.hxx>
#endif
#ifndef _SVX_ACCESSIBILITY_ACCESSIBLE_SHAPE_HXX
#include <svx/AccessibleShape.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLERELATIONTYPE_HPP_
#include <drafts/com/sun/star/accessibility/AccessibleRelationType.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEEVENTID_HPP_
#include <drafts/com/sun/star/accessibility/AccessibleEventId.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_
#include <drafts/com/sun/star/accessibility/AccessibleStateType.hpp>
#endif
#ifndef _COM_SUN_STAR_DOCUMENT_XEVENTBROADCASTER_HPP_
#include <com/sun/star/document/XEventBroadcaster.hpp>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
using namespace ::com::sun::star::uno;
using namespace ::drafts::com::sun::star::accessibility;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::document;
using namespace ::rtl;
struct SwFrmFunc
{
sal_Bool operator()( const SwFrm * p1,
const SwFrm * p2) const
{
return p1 < p2;
}
};
typedef ::std::map < const SwFrm *, WeakReference < XAccessible >, SwFrmFunc > _SwAccessibleContextMap_Impl;
class SwAccessibleContextMap_Impl: public _SwAccessibleContextMap_Impl
{
public:
#ifndef PRODUCT
sal_Bool mbLocked;
#endif
SwAccessibleContextMap_Impl()
#ifndef PRODUCT
: mbLocked( sal_False )
#endif
{}
};
//------------------------------------------------------------------------------
class SwDrawModellListener_Impl : public SfxListener,
public ::cppu::WeakImplHelper1< XEventBroadcaster >
{
mutable ::osl::Mutex maListenerMutex;
::cppu::OInterfaceContainerHelper maEventListeners;
SdrModel *mpDrawModel;
public:
SwDrawModellListener_Impl( SdrModel *pDrawModel );
virtual ~SwDrawModellListener_Impl();
virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
void Dispose();
};
SwDrawModellListener_Impl::SwDrawModellListener_Impl( SdrModel *pDrawModel ) :
maEventListeners( maListenerMutex ),
mpDrawModel( pDrawModel )
{
StartListening( *mpDrawModel );
}
SwDrawModellListener_Impl::~SwDrawModellListener_Impl()
{
EndListening( *mpDrawModel );
}
void SAL_CALL SwDrawModellListener_Impl::addEventListener( const Reference< XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
{
maEventListeners.addInterface( xListener );
}
void SAL_CALL SwDrawModellListener_Impl::removeEventListener( const Reference< XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
{
maEventListeners.removeInterface( xListener );
}
void SwDrawModellListener_Impl::Notify( SfxBroadcaster& rBC,
const SfxHint& rHint )
{
// do not broadcast notifications for writer fly frames, because there
// are no shapes that need to know about them.
const SdrHint *pSdrHint = PTR_CAST( SdrHint, &rHint );
if( !pSdrHint ||
(pSdrHint->GetObject() && pSdrHint->GetObject()->IsWriterFlyFrame()) )
return;
ASSERT( mpDrawModel, "draw model listener is disposed" );
if( !mpDrawModel )
return;
EventObject aEvent;
if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) )
return;
::cppu::OInterfaceIteratorHelper aIter( maEventListeners );
while( aIter.hasMoreElements() )
{
Reference < XEventListener > xListener( aIter.next(),
UNO_QUERY );
try
{
xListener->notifyEvent( aEvent );
}
catch( ::com::sun::star::uno::RuntimeException& r )
{
#ifdef DEBUG
ByteString aError( "Runtime exception caught while notifying shape.:\n" );
aError += ByteString( String( r.Message), RTL_TEXTENCODING_ASCII_US );
DBG_ERROR( aError.GetBuffer() );
#endif
}
}
}
void SwDrawModellListener_Impl::Dispose()
{
mpDrawModel = 0;
}
//------------------------------------------------------------------------------
struct SwShapeFunc
{
sal_Bool operator()( const SdrObject * p1,
const SdrObject * p2) const
{
return p1 < p2;
}
};
typedef ::std::map < const SdrObject *, WeakReference < XAccessible >, SwShapeFunc > _SwAccessibleShapeMap_Impl;
typedef ::std::pair < const SdrObject *, ::vos::ORef < accessibility::AccessibleShape > > SwAccessibleObjShape_Impl;
class SwAccessibleShapeMap_Impl: public _SwAccessibleShapeMap_Impl
{
accessibility::AccessibleShapeTreeInfo maInfo;
public:
#ifndef PRODUCT
sal_Bool mbLocked;
#endif
SwAccessibleShapeMap_Impl( SwAccessibleMap *pMap )
#ifndef PRODUCT
: mbLocked( sal_False )
#endif
{
maInfo.SetSdrView( pMap->GetShell()->GetDrawView() );
maInfo.SetWindow( pMap->GetShell()->GetWin() );
maInfo.SetViewForwarder( pMap );
Reference < XEventBroadcaster > xModelBroadcaster =
new SwDrawModellListener_Impl(
pMap->GetShell()->GetDoc()->MakeDrawModel() );
maInfo.SetControllerBroadcaster( xModelBroadcaster );
}
~SwAccessibleShapeMap_Impl();
const accessibility::AccessibleShapeTreeInfo& GetInfo() const { return maInfo; }
SwAccessibleObjShape_Impl *Copy( size_t& rSize,
const SwFEShell *pFESh = 0,
SwAccessibleObjShape_Impl **pSelShape = 0 ) const;
};
SwAccessibleShapeMap_Impl::~SwAccessibleShapeMap_Impl()
{
Reference < XEventBroadcaster > xBrd( maInfo.GetControllerBroadcaster() );
if( xBrd.is() )
static_cast < SwDrawModellListener_Impl * >( xBrd.get() )->Dispose();
}
SwAccessibleObjShape_Impl
*SwAccessibleShapeMap_Impl::Copy(
size_t& rSize, const SwFEShell *pFESh,
SwAccessibleObjShape_Impl **pSelStart ) const
{
SwAccessibleObjShape_Impl *pShapes = 0;
SwAccessibleObjShape_Impl *pSelShape = 0;
sal_uInt16 nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
rSize = size();
if( rSize > 0 )
{
pShapes =
new SwAccessibleObjShape_Impl[rSize];
const_iterator aIter = begin();
const_iterator aEndIter = end();
SwAccessibleObjShape_Impl *pShape = pShapes;
pSelShape = &(pShapes[rSize]);
while( aIter != aEndIter )
{
const SdrObject *pObj = (*aIter).first;
Reference < XAccessible > xAcc( (*aIter).second );
if( nSelShapes && pFESh->IsObjSelected( *pObj ) )
{
// selected objects are inserted from the back
--pSelShape;
pSelShape->first = pObj;
pSelShape->second =
static_cast < accessibility::AccessibleShape* >(
xAcc.get() );
--nSelShapes;
}
else
{
pShape->first = pObj;
pShape->second =
static_cast < accessibility::AccessibleShape* >(
xAcc.get() );
++pShape;
}
++aIter;
}
ASSERT( pSelShape == pShape, "copying shapes went wrong!" );
}
if( pSelStart )
*pSelStart = pSelShape;
return pShapes;
}
//------------------------------------------------------------------------------
struct SwAccessibleEvent_Impl
{
public:
enum EventType { CARET_OR_STATES, INVALID_CONTENT, POS_CHANGED,
CHILD_POS_CHANGED, SHAPE_SELECTION, DISPOSE };
private:
SwRect maOldBox; // the old bounds for CHILD_POS_CHANGED
// and POS_CHANGED
WeakReference < XAccessible > mxAcc; // The object that fires the event
SwFrmOrObj maFrmOrObj; // the child for CHILD_POS_CHANGED and
// the same as xAcc for any other
// event type
EventType meType; // The event type
sal_uInt8 mnStates; // check states or update caret pos
SwAccessibleEvent_Impl& operator==( const SwAccessibleEvent_Impl& );
public:
SwAccessibleEvent_Impl( EventType eT, SwAccessibleContext *pA,
const SwFrmOrObj& rFrmOrObj ) :
meType( eT ), mxAcc( pA ), maFrmOrObj( rFrmOrObj ), mnStates( 0 )
{}
SwAccessibleEvent_Impl( EventType eT, const SwFrmOrObj& rFrmOrObj ) :
meType( eT ), maFrmOrObj( rFrmOrObj ), mnStates( 0 )
{
ASSERT( SwAccessibleEvent_Impl::DISPOSE == meType,
"wrong event constructor, DISPOSE only" );
}
SwAccessibleEvent_Impl( EventType eT ) :
meType( eT ), mnStates( 0 )
{
ASSERT( SwAccessibleEvent_Impl::SHAPE_SELECTION == meType,
"wrong event constructor, SHAPE_SELECTION only" );
}
SwAccessibleEvent_Impl( EventType eT, SwAccessibleContext *pA,
const SwFrmOrObj& rFrmOrObj, const SwRect& rR ) :
meType( eT ), mxAcc( pA ), maFrmOrObj( rFrmOrObj ), maOldBox( rR ),
mnStates( 0 )
{
ASSERT( SwAccessibleEvent_Impl::CHILD_POS_CHANGED == meType ||
SwAccessibleEvent_Impl::POS_CHANGED == meType,
"wrong event constructor, (CHILD_)POS_CHANGED only" );
}
SwAccessibleEvent_Impl( EventType eT, SwAccessibleContext *pA,
const SwFrmOrObj& rFrmOrObj, sal_uInt8 nSt ) :
meType( eT ), mxAcc( pA ), maFrmOrObj( rFrmOrObj ), mnStates( nSt )
{
ASSERT( SwAccessibleEvent_Impl::CARET_OR_STATES == meType,
"wrong event constructor, CARET_OR_STATES only" );
}
inline void SetType( EventType eT ){ meType = eT; }
inline EventType GetType() const { return meType; }
inline ::vos::ORef < SwAccessibleContext > GetContext() const;
inline const SwRect& GetOldBox() const { return maOldBox; }
inline void SetOldBox( const SwRect& rOldBox ) { maOldBox = rOldBox; }
inline const SwFrmOrObj& GetFrmOrObj() const { return maFrmOrObj; }
inline void SetStates( sal_uInt8 nSt ) { mnStates |= nSt; }
inline sal_Bool IsUpdateCursorPos() const { return (mnStates & ACC_STATE_CARET) != 0; }
inline sal_Bool IsInvalidateStates() const { return (mnStates & ACC_STATE_MASK) != 0; }
inline sal_Bool IsInvalidateRelation() const { return (mnStates & ACC_STATE_RELATION_MASK) != 0; }
inline sal_uInt8 GetStates() const { return mnStates & ACC_STATE_MASK; }
inline sal_uInt8 GetAllStates() const { return mnStates; }
};
inline ::vos::ORef < SwAccessibleContext >
SwAccessibleEvent_Impl::GetContext() const
{
Reference < XAccessible > xTmp( mxAcc );
::vos::ORef < SwAccessibleContext > xAccImpl(
static_cast< SwAccessibleContext * >( xTmp.get() ) );
return xAccImpl;
}
//------------------------------------------------------------------------------
typedef ::std::list < SwAccessibleEvent_Impl > _SwAccessibleEventList_Impl;
class SwAccessibleEventList_Impl: public _SwAccessibleEventList_Impl
{
sal_Bool mbFiring;
public:
SwAccessibleEventList_Impl() : mbFiring( sal_False ) {}
inline void SetFiring() { mbFiring = sal_True; }
inline sal_Bool IsFiring() const { return mbFiring; }
};
//------------------------------------------------------------------------------
// The shape list is filled if an accessible shape is destroyed. It
// simply keeps a reference to the accessible shape's XShape. These
// references are destroyed within the EndAction when firing events,
// There are twp reason for this. First of all, a new accessible shape
// for the XShape might be created soon. It's then cheaper if the XShape
// still exists. The other reason are situations where an accessible shape
// is destroyed within an SwFrmFmt::Modify. In this case, destryoing
// the XShape at the same time (indirectly by destroying the accessible
// shape) leads to an assert, because a client of the Modify is destroyed
// within a Modify call.
typedef ::std::list < Reference < XShape > > _SwShapeList_Impl;
class SwShapeList_Impl: public _SwShapeList_Impl
{
public:
SwShapeList_Impl() {}
};
//------------------------------------------------------------------------------
struct SwFrmOrObjFunc
{
sal_Bool operator()( const SwFrmOrObj& r1,
const SwFrmOrObj& r2 ) const
{
const void *p1 = r1.GetSwFrm()
? static_cast < const void * >( r1.GetSwFrm())
: static_cast < const void * >( r1.GetSdrObject() );
const void *p2 = r2.GetSwFrm()
? static_cast < const void * >( r2.GetSwFrm())
: static_cast < const void * >( r2.GetSdrObject() );
return p1 < p2;
}
};
typedef ::std::map < SwFrmOrObj, SwAccessibleEventList_Impl::iterator,
SwFrmOrObjFunc > _SwAccessibleEventMap_Impl;
class SwAccessibleEventMap_Impl: public _SwAccessibleEventMap_Impl
{
};
//------------------------------------------------------------------------------
static sal_Bool AreInSameTable( const Reference< XAccessible >& rAcc,
const SwFrm *pFrm )
{
sal_Bool bRet = sal_False;
if( pFrm && pFrm->IsCellFrm() && rAcc.is() )
{
// Is it in the same table? We check that
// by comparing the last table frame in the
// follow chain, because that's cheaper than
// searching the first one.
SwAccessibleContext *pAccImpl =
static_cast< SwAccessibleContext *>( rAcc.get() );
if( pAccImpl->GetFrm()->IsCellFrm() )
{
const SwTabFrm *pTabFrm1 = pAccImpl->GetFrm()->FindTabFrm();
while( pTabFrm1->GetFollow() )
pTabFrm1 = pTabFrm1->GetFollow();
const SwTabFrm *pTabFrm2 = pFrm->FindTabFrm();
while( pTabFrm2->GetFollow() )
pTabFrm2 = pTabFrm2->GetFollow();
bRet = (pTabFrm1 == pTabFrm2);
}
}
return bRet;
}
void SwAccessibleMap::FireEvent( const SwAccessibleEvent_Impl& rEvent )
{
::vos::ORef < SwAccessibleContext > xAccImpl( rEvent.GetContext() );
if( SwAccessibleEvent_Impl::SHAPE_SELECTION == rEvent.GetType() )
{
DoInvalidateShapeSelection();
}
else if( xAccImpl.isValid() && xAccImpl->GetFrm() )
{
switch( rEvent.GetType() )
{
case SwAccessibleEvent_Impl::INVALID_CONTENT:
xAccImpl->InvalidateContent();
break;
case SwAccessibleEvent_Impl::POS_CHANGED:
xAccImpl->InvalidatePosOrSize( rEvent.GetOldBox() );
break;
case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
xAccImpl->InvalidateChildPosOrSize( rEvent.GetFrmOrObj(),
rEvent.GetOldBox() );
break;
case SwAccessibleEvent_Impl::DISPOSE:
ASSERT( xAccImpl.isValid(),
"dispose event has been stored" );
break;
}
if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
{
if( rEvent.IsUpdateCursorPos() )
xAccImpl->InvalidateCursorPos();
if( rEvent.IsInvalidateStates() )
xAccImpl->InvalidateStates( rEvent.GetStates() );
if( rEvent.IsInvalidateRelation() )
xAccImpl->InvalidateRelation(
(rEvent.GetAllStates() & ACC_STATE_RELATION_FROM) != 0 ?
AccessibleEventId::CONTENT_FLOWS_FROM_EVENT :
AccessibleEventId::CONTENT_FLOWS_TO_EVENT );
}
}
}
void SwAccessibleMap::AppendEvent( const SwAccessibleEvent_Impl& rEvent )
{
vos::OGuard aGuard( maEventMutex );
if( !mpEvents )
mpEvents = new SwAccessibleEventList_Impl;
if( !mpEventMap )
mpEventMap = new SwAccessibleEventMap_Impl;
if( mpEvents->IsFiring() )
{
// While events are fired new ones are generated. They have to be fired
// now. This does not work for DISPOSE events!
ASSERT( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE,
"dispose event while firing events" );
FireEvent( rEvent );
}
else
{
SwAccessibleEventMap_Impl::iterator aIter =
mpEventMap->find( rEvent.GetFrmOrObj() );
if( aIter != mpEventMap->end() )
{
SwAccessibleEvent_Impl aEvent( *(*aIter).second );
ASSERT( aEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE,
"dispose events should not be stored" );
sal_Bool bAppendEvent = sal_True;
switch( rEvent.GetType() )
{
case SwAccessibleEvent_Impl::CARET_OR_STATES:
// A CARET_OR_STATES event is added to any other
// event only. It is broadcasted after any other event, so the
// event should be put to the back.
ASSERT( aEvent.GetType() !=
SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
"invalid event combination" );
aEvent.SetStates( rEvent.GetAllStates() );
break;
case SwAccessibleEvent_Impl::INVALID_CONTENT:
// An INVALID_CONTENT event overwrites a CARET_OR_STATES
// event (but keeps its flags) and it is contained in a
// POS_CHANGED event.
// Therefor, the event's type has to be adapted and the event
// has to be put at the end.
ASSERT( aEvent.GetType() !=
SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
"invalid event combination" );
if( aEvent.GetType() ==
SwAccessibleEvent_Impl::CARET_OR_STATES )
aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT );
break;
case SwAccessibleEvent_Impl::POS_CHANGED:
// A pos changed event overwrites CARET_STATES (keeping its
// flags) as well as INVALID_CONTENT. The old box position
// has to be stored however if the old event is not a
// POS_CHANGED itself.
ASSERT( aEvent.GetType() !=
SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
"invalid event combination" );
if( aEvent.GetType() != SwAccessibleEvent_Impl::POS_CHANGED )
aEvent.SetOldBox( rEvent.GetOldBox() );
aEvent.SetType( SwAccessibleEvent_Impl::POS_CHANGED );
break;
case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
// CHILD_POS_CHANGED events can only follow CHILD_POS_CHANGED
// events. The only action that needs to be done again is
// to put the old event to the back. The new one cannot be used,
// because we are interested in the old frame bounds.
ASSERT( aEvent.GetType() ==
SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
"invalid event combination" );
break;
case SwAccessibleEvent_Impl::SHAPE_SELECTION:
ASSERT( aEvent.GetType() ==
SwAccessibleEvent_Impl::SHAPE_SELECTION,
"invalid event combination" );
break;
case SwAccessibleEvent_Impl::DISPOSE:
// DISPOSE events overwrite all others. They are not stored
// but executed immediatly to avoid broadcasting of
// defunctional objects. So what needs to be done here is to
// remove all events for the frame in question.
bAppendEvent = sal_False;
break;
}
if( bAppendEvent )
{
mpEvents->erase( (*aIter).second );
(*aIter).second = mpEvents->insert( mpEvents->end(), aEvent );
}
else
{
mpEvents->erase( (*aIter).second );
mpEventMap->erase( aIter );
}
}
else if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
{
SwAccessibleEventMap_Impl::value_type aEntry( rEvent.GetFrmOrObj(),
mpEvents->insert( mpEvents->end(), rEvent ) );
mpEventMap->insert( aEntry );
}
}
}
void SwAccessibleMap::InvalidateCursorPosition(
const Reference< XAccessible >& rAcc )
{
SwAccessibleContext *pAccImpl =
static_cast< SwAccessibleContext *>( rAcc.get() );
ASSERT( pAccImpl, "no caret context" );
ASSERT( pAccImpl->GetFrm(), "caret context is disposed" );
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::CARET_OR_STATES, pAccImpl,
pAccImpl->GetFrm(), ACC_STATE_CARET );
AppendEvent( aEvent );
}
else
{
pAccImpl->InvalidateCursorPos();
}
}
void SwAccessibleMap::InvalidateShapeSelection()
{
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::SHAPE_SELECTION );
AppendEvent( aEvent );
}
else
{
DoInvalidateShapeSelection();
}
}
void SwAccessibleMap::DoInvalidateShapeSelection()
{
SwAccessibleObjShape_Impl *pShapes = 0;
SwAccessibleObjShape_Impl *pSelShape = 0;
size_t nShapes = 0;
const ViewShell *pVSh = GetShell();
const SwFEShell *pFESh = pVSh->ISA( SwFEShell ) ?
static_cast< const SwFEShell * >( pVSh ) : 0;
sal_uInt16 nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
{
vos::OGuard aGuard( maMutex );
if( mpShapeMap )
pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
}
if( pShapes )
{
::std::list< const SwFrm * > aParents;
sal_Bool bChanged = sal_False;
Window *pWin = GetShell()->GetWin();
sal_Bool bFocused = pWin && pWin->HasFocus();
SwAccessibleObjShape_Impl *pShape = pShapes;
while( nShapes )
{
if( pShape->second.isValid() )
{
sal_Bool bChanged;
if( pShape >= pSelShape )
{
bChanged =
pShape->second->SetState( AccessibleStateType::SELECTED );
if( bFocused && 1 == nSelShapes )
pShape->second->SetState( AccessibleStateType::FOCUSED );
else
pShape->second->ResetState( AccessibleStateType::FOCUSED );
}
else
{
bChanged =
pShape->second->ResetState( AccessibleStateType::SELECTED );
pShape->second->ResetState( AccessibleStateType::FOCUSED );
}
if( bChanged )
{
SwFrmOrObj aFrmOrObj( pShape->first );
SwFrmOrObj aParent =
SwAccessibleFrame::GetParent( aFrmOrObj,
GetShell()->IsPreView() );
aParents.push_back( aParent.GetSwFrm() );
}
}
--nShapes;
++pShape;
}
if( aParents.size() > 0 )
{
::std::list< const SwFrm * >::const_iterator aIter = aParents.begin();
::std::list< const SwFrm * >::const_iterator aEndIter = aParents.end();
while( aIter != aEndIter )
{
::vos::ORef< SwAccessibleContext > xParentAccImpl;
{
vos::OGuard aGuard( maMutex );
if( mpFrmMap )
{
SwAccessibleContextMap_Impl::const_iterator aMapIter =
mpFrmMap->find( *aIter );
if( aMapIter != mpFrmMap->end() )
{
Reference < XAccessible > xAcc( (*aMapIter).second );
xParentAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
}
}
}
if( xParentAccImpl.isValid() )
{
AccessibleEventObject aEvent;
aEvent.EventId = AccessibleEventId::ACCESSIBLE_SELECTION_EVENT;
xParentAccImpl->FireAccessibleEvent( aEvent );
}
++aIter;
}
}
delete[] pShapes;
}
}
void SwAccessibleMap::DoInvalidateShapeFocus()
{
const ViewShell *pVSh = GetShell();
const SwFEShell *pFESh = pVSh->ISA( SwFEShell ) ?
static_cast< const SwFEShell * >( pVSh ) : 0;
sal_uInt16 nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
if( nSelShapes != 1 )
return;
SwAccessibleObjShape_Impl *pShapes = 0;
SwAccessibleObjShape_Impl *pSelShape = 0;
size_t nShapes = 0;
{
vos::OGuard aGuard( maMutex );
if( mpShapeMap )
pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
}
if( pShapes )
{
Window *pWin = GetShell()->GetWin();
sal_Bool bFocused = pWin && pWin->HasFocus();
SwAccessibleObjShape_Impl *pShape = pShapes;
while( nShapes )
{
if( pShape->second.isValid() )
{
if( bFocused && pShape >= pSelShape )
pShape->second->SetState( AccessibleStateType::FOCUSED );
else
pShape->second->ResetState( AccessibleStateType::FOCUSED );
}
--nShapes;
++pShape;
}
delete[] pShapes;
}
}
SwAccessibleMap::SwAccessibleMap( ViewShell *pSh ) :
mpFrmMap( 0 ),
mpShapeMap( 0 ),
mpShapes( 0 ),
mpEvents( 0 ),
mpEventMap( 0 ),
mpVSh( pSh ),
mnPara( 1 ),
mnFootnote( 1 ),
mnEndnote( 1 ),
mbShapeSelected( sal_False ),
mpPreview( NULL )
{
pSh->GetLayout()->AddAccessibleShell();
}
SwAccessibleMap::~SwAccessibleMap()
{
Reference < XAccessible > xAcc;
{
vos::OGuard aGuard( maMutex );
if( mpFrmMap )
{
const SwRootFrm *pRootFrm = GetShell()->GetLayout();
SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->find( pRootFrm );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
if( !xAcc.is() )
xAcc = new SwAccessibleDocument( this );
}
}
SwAccessibleDocument *pAcc =
static_cast< SwAccessibleDocument * >( xAcc.get() );
pAcc->Dispose( sal_True );
{
vos::OGuard aGuard( maMutex );
#ifndef PRODUCT
ASSERT( !mpFrmMap || mpFrmMap->empty(),
"Frame map should be empty after disposing the root frame" );
if( mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->begin();
while( aIter != mpFrmMap->end() )
{
Reference < XAccessible > xTmp = (*aIter).second;
if( xTmp.is() )
{
SwAccessibleContext *pTmp =
static_cast< SwAccessibleContext * >( xTmp.get() );
}
++aIter;
}
}
ASSERT( !mpShapeMap || mpShapeMap->empty(),
"Object map should be empty after disposing the root frame" );
if( mpShapeMap )
{
SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->begin();
while( aIter != mpShapeMap->end() )
{
Reference < XAccessible > xTmp = (*aIter).second;
if( xTmp.is() )
{
accessibility::AccessibleShape *pTmp =
static_cast< accessibility::AccessibleShape* >( xTmp.get() );
}
++aIter;
}
}
#endif
delete mpFrmMap;
mpFrmMap = 0;
delete mpShapeMap;
mpShapeMap = 0;
delete mpShapes;
mpShapes = 0;
}
delete mpPreview;
mpPreview = NULL;
{
vos::OGuard aGuard( maEventMutex );
#ifndef PRODUCT
ASSERT( !(mpEvents || mpEventMap), "pending events" );
if( mpEvents )
{
SwAccessibleEventList_Impl::iterator aIter = mpEvents->begin();
while( aIter != mpEvents->end() )
{
const SwAccessibleEvent_Impl& rEvent = *aIter;
++aIter;
}
}
if( mpEventMap )
{
SwAccessibleEventMap_Impl::iterator aIter = mpEventMap->begin();
while( aIter != mpEventMap->end() )
{
const SwFrmOrObj& rFrmOrObj = (*aIter).first;
const SwAccessibleEvent_Impl& rEvent = *(*aIter).second;
++aIter;
}
}
#endif
delete mpEventMap;
mpEventMap = 0;
delete mpEvents;
mpEvents = 0;
}
mpVSh->GetLayout()->RemoveAccessibleShell();
}
Reference< XAccessible > SwAccessibleMap::_GetDocumentView(
sal_Bool bPagePreview )
{
Reference < XAccessible > xAcc;
sal_Bool bSetVisArea = sal_False;
{
vos::OGuard aGuard( maMutex );
if( !mpFrmMap )
{
mpFrmMap = new SwAccessibleContextMap_Impl;
#ifndef PRODUCT
mpFrmMap->mbLocked = sal_False;
#endif
}
#ifndef PRODUCT
ASSERT( !mpFrmMap->mbLocked, "Map is locked" );
mpFrmMap->mbLocked = sal_True;
#endif
const SwRootFrm *pRootFrm = GetShell()->GetLayout();
SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->find( pRootFrm );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
if( xAcc.is() )
{
bSetVisArea = sal_True; // Set VisArea when map mutex is not
// locked
}
else
{
if( bPagePreview )
xAcc = new SwAccessiblePreview( this );
else
xAcc = new SwAccessibleDocument( this );
if( aIter != mpFrmMap->end() )
{
(*aIter).second = xAcc;
}
else
{
SwAccessibleContextMap_Impl::value_type aEntry( pRootFrm, xAcc );
mpFrmMap->insert( aEntry );
}
}
#ifndef PRODUCT
mpFrmMap->mbLocked = sal_False;
#endif
}
if( bSetVisArea )
{
SwAccessibleDocumentBase *pAcc =
static_cast< SwAccessibleDocumentBase * >( xAcc.get() );
pAcc->SetVisArea();
}
return xAcc;
}
Reference< XAccessible > SwAccessibleMap::GetDocumentView( )
{
return _GetDocumentView( sal_False );
}
Reference<XAccessible> SwAccessibleMap::GetDocumentPreview(
sal_uInt8 nRow,
sal_uInt8 nColumn,
sal_Int16 nStartPage,
const Size& rPageSize,
const Point& rFreePoint,
const Fraction& rScale,
sal_uInt16 nSelectedPage )
{
// create & update preview data object
if( mpPreview == NULL )
mpPreview = new SwAccPreviewData();
mpPreview->Update( nRow, nColumn, nStartPage,
rPageSize, rFreePoint, rScale, GetShell(),
nSelectedPage );
Reference<XAccessible> xAcc = _GetDocumentView( sal_True );
return xAcc;
}
Reference< XAccessible> SwAccessibleMap::GetContext( const SwFrm *pFrm,
sal_Bool bCreate )
{
Reference < XAccessible > xAcc;
Reference < XAccessible > xOldCursorAcc;
sal_Bool bOldShapeSelected = sal_False;
{
vos::OGuard aGuard( maMutex );
if( !mpFrmMap && bCreate )
mpFrmMap = new SwAccessibleContextMap_Impl;
if( mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter = mpFrmMap->find( pFrm );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
if( !xAcc.is() && bCreate )
{
SwAccessibleContext *pAcc = 0;
switch( pFrm->GetType() )
{
case FRM_TXT:
pAcc = new SwAccessibleParagraph( this, mnPara++,
static_cast< const SwTxtFrm * >( pFrm ) );
break;
case FRM_HEADER:
pAcc = new SwAccessibleHeaderFooter( this,
static_cast< const SwHeaderFrm *>( pFrm ) );
break;
case FRM_FOOTER:
pAcc = new SwAccessibleHeaderFooter( this,
static_cast< const SwFooterFrm *>( pFrm ) );
break;
case FRM_FTN:
{
const SwFtnFrm *pFtnFrm =
static_cast < const SwFtnFrm * >( pFrm );
sal_Bool bIsEndnote =
SwAccessibleFootnote::IsEndnote( pFtnFrm );
pAcc = new SwAccessibleFootnote( this, bIsEndnote,
(bIsEndnote ? mnEndnote++ : mnFootnote++),
pFtnFrm );
}
break;
case FRM_FLY:
{
const SwFlyFrm *pFlyFrm =
static_cast < const SwFlyFrm * >( pFrm );
switch( SwAccessibleFrameBase::GetNodeType( pFlyFrm ) )
{
case ND_GRFNODE:
pAcc = new SwAccessibleGraphic( this, pFlyFrm );
break;
case ND_OLENODE:
pAcc = new SwAccessibleEmbeddedObject( this, pFlyFrm );
break;
default:
pAcc = new SwAccessibleTextFrame( this, pFlyFrm );
break;
}
}
break;
case FRM_CELL:
pAcc = new SwAccessibleCell( this,
static_cast< const SwCellFrm *>( pFrm ) );
break;
case FRM_TAB:
pAcc = new SwAccessibleTable( this,
static_cast< const SwTabFrm *>( pFrm ) );
break;
case FRM_PAGE:
DBG_ASSERT( GetShell()->IsPreView(),
"accessible page frames only in PagePreview" );
pAcc = new SwAccessiblePage( this, pFrm );
break;
}
xAcc = pAcc;
ASSERT( xAcc.is(), "unknown frame type" );
if( xAcc.is() )
{
if( aIter != mpFrmMap->end() )
{
(*aIter).second = xAcc;
}
else
{
SwAccessibleContextMap_Impl::value_type aEntry( pFrm, xAcc );
mpFrmMap->insert( aEntry );
}
if( pAcc->HasCursor() &&
!AreInSameTable( mxCursorContext, pFrm ) )
{
// If the new context has the focus, and if we know
// another context that had the focus, then the focus
// just moves from the old context to the new one. We
// have to send a focus event and a caret event for
// the old context then. We have to to that know,
// because after we have left this method, anyone might
// call getStates for the new context and will get a
// focused state then. Sending the focus changes event
// after that seems to be strange. However, we cannot
// send a focus event fo the new context now, because
// noone except us knows it. In any case, we remeber
// the new context as the one that has the focus
// currently.
xOldCursorAcc = mxCursorContext;
mxCursorContext = xAcc;
bOldShapeSelected = mbShapeSelected;
mbShapeSelected = sal_False;
}
}
}
}
}
// Invalidate focus for old object when map is not locked
if( xOldCursorAcc.is() )
InvalidateCursorPosition( xOldCursorAcc );
if( bOldShapeSelected )
InvalidateShapeSelection();
return xAcc;
}
::vos::ORef < SwAccessibleContext > SwAccessibleMap::GetContextImpl(
const SwFrm *pFrm,
sal_Bool bCreate )
{
Reference < XAccessible > xAcc( GetContext( pFrm, bCreate ) );
::vos::ORef < SwAccessibleContext > xAccImpl(
static_cast< SwAccessibleContext * >( xAcc.get() ) );
return xAccImpl;
}
Reference< XAccessible> SwAccessibleMap::GetContext(
const SdrObject *pObj,
SwAccessibleContext *pParentImpl,
sal_Bool bCreate )
{
Reference < XAccessible > xAcc;
Reference < XAccessible > xOldCursorAcc;
{
vos::OGuard aGuard( maMutex );
if( !mpShapeMap && bCreate )
mpShapeMap = new SwAccessibleShapeMap_Impl( this );
if( mpShapeMap )
{
SwAccessibleShapeMap_Impl::iterator aIter =
mpShapeMap->find( pObj );
if( aIter != mpShapeMap->end() )
xAcc = (*aIter).second;
if( !xAcc.is() && bCreate )
{
accessibility::AccessibleShape *pAcc = 0;
Reference < XShape > xShape(
const_cast< SdrObject * >( pObj )->getUnoShape(),
UNO_QUERY );
if( xShape.is() )
{
accessibility::ShapeTypeHandler& rShapeTypeHandler =
accessibility::ShapeTypeHandler::Instance();
Reference < XAccessible > xParent( pParentImpl );
::accessibility::AccessibleShapeInfo aShapeInfo(
xShape, xParent, this );
pAcc = rShapeTypeHandler.CreateAccessibleObject(
aShapeInfo, mpShapeMap->GetInfo() );
}
xAcc = pAcc;
ASSERT( xAcc.is(), "unknown shape type" );
if( xAcc.is() )
{
pAcc->Init();
if( aIter != mpShapeMap->end() )
{
(*aIter).second = xAcc;
}
else
{
SwAccessibleShapeMap_Impl::value_type aEntry( pObj,
xAcc );
mpShapeMap->insert( aEntry );
}
// TODO: focus!!!
}
}
}
}
// Invalidate focus for old object when map is not locked
if( xOldCursorAcc.is() )
InvalidateCursorPosition( xOldCursorAcc );
return xAcc;
}
::vos::ORef < accessibility::AccessibleShape > SwAccessibleMap::GetContextImpl(
const SdrObject *pObj,
SwAccessibleContext *pParentImpl,
sal_Bool bCreate )
{
Reference < XAccessible > xAcc( GetContext( pObj, pParentImpl, bCreate ) );
::vos::ORef < accessibility::AccessibleShape > xAccImpl(
static_cast< accessibility::AccessibleShape* >( xAcc.get() ) );
return xAccImpl;
}
void SwAccessibleMap::RemoveContext( const SwFrm *pFrm )
{
vos::OGuard aGuard( maMutex );
if( mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( pFrm );
if( aIter != mpFrmMap->end() )
{
mpFrmMap->erase( aIter );
// Remove reference to old caret object. Though mxCursorContext
// is a weak reference and cleared automatically, clearing it
// directly makes sure to not keep a defunctional object.
Reference < XAccessible > xOldAcc( mxCursorContext );
if( xOldAcc.is() )
{
SwAccessibleContext *pOldAccImpl =
static_cast< SwAccessibleContext *>( xOldAcc.get() );
ASSERT( pOldAccImpl->GetFrm(), "old caret context is disposed" );
if( pOldAccImpl->GetFrm() == pFrm )
{
xOldAcc.clear(); // get an empty ref
mxCursorContext = xOldAcc;
}
}
if( mpFrmMap->empty() )
{
delete mpFrmMap;
mpFrmMap = 0;
}
}
}
}
void SwAccessibleMap::RemoveContext( const SdrObject *pObj )
{
vos::OGuard aGuard( maMutex );
if( mpShapeMap )
{
SwAccessibleShapeMap_Impl::iterator aIter =
mpShapeMap->find( pObj );
if( aIter != mpShapeMap->end() )
{
mpShapeMap->erase( aIter );
// The shape selection flag is not cleared, but one might do
// so but has to make sure that the removed context is the one
// that is selected.
if( mpShapeMap->empty() )
{
delete mpShapeMap;
mpShapeMap = 0;
}
}
}
}
void SwAccessibleMap::Dispose( const SwFrm *pFrm, const SdrObject *pObj,
sal_Bool bRecursive )
{
SwFrmOrObj aFrmOrObj( pFrm, pObj );
// Indeed, the following assert checks the frame's accessible flag,
// because that's the one that is evaluated in the layout. The frame
// might not be accessible anyway. That's the case for cell frames that
// contain further cells.
ASSERT( !aFrmOrObj.GetSwFrm() || aFrmOrObj.GetSwFrm()->IsAccessibleFrm(),
"non accessible frame should be disposed" );
::vos::ORef< SwAccessibleContext > xAccImpl;
::vos::ORef< SwAccessibleContext > xParentAccImpl;
::vos::ORef< ::accessibility::AccessibleShape > xShapeAccImpl;
if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) )
{
// get accessible context for frame
{
vos::OGuard aGuard( maMutex );
// First of all look for an accessible context for a frame
if( aFrmOrObj.GetSwFrm() && mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( aFrmOrObj.GetSwFrm() );
if( aIter != mpFrmMap->end() )
{
Reference < XAccessible > xAcc( (*aIter).second );
xAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
}
}
if( !xAccImpl.isValid() && mpFrmMap )
{
// If there is none, look if the parent is accessible.
const SwFrm *pParent =
SwAccessibleFrame::GetParent( aFrmOrObj,
GetShell()->IsPreView());
if( pParent )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( pParent );
if( aIter != mpFrmMap->end() )
{
Reference < XAccessible > xAcc( (*aIter).second );
xParentAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
}
}
}
if( !xParentAccImpl.isValid() && !aFrmOrObj.GetSwFrm() &&
mpShapeMap )
{
SwAccessibleShapeMap_Impl::iterator aIter =
mpShapeMap->find( aFrmOrObj.GetSdrObject() );
if( aIter != mpShapeMap->end() )
{
Reference < XAccessible > xAcc( (*aIter).second );
xShapeAccImpl =
static_cast< accessibility::AccessibleShape *>( xAcc.get() );
}
}
if( pObj && GetShell()->ActionPend() &&
(xParentAccImpl.isValid() || xShapeAccImpl.isValid()) )
{
// Keep a reference to the XShape to avoid that it
// is deleted with a SwFrmFmt::Modify.
Reference < XShape > xShape(
const_cast< SdrObject * >( pObj )->getUnoShape(),
UNO_QUERY );
if( xShape.is() )
{
if( !mpShapes )
mpShapes = new SwShapeList_Impl;
mpShapes->push_back( xShape );
}
}
}
// remove events stored for the frame
{
vos::OGuard aGuard( maEventMutex );
if( mpEvents )
{
SwAccessibleEventMap_Impl::iterator aIter =
mpEventMap->find( aFrmOrObj );
if( aIter != mpEventMap->end() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::DISPOSE, aFrmOrObj );
AppendEvent( aEvent );
}
}
}
// If the frame is accessible and there is a context for it, dispose
// the frame. If the frame is no context for it but disposing should
// take place recursive, the frame's children have to be disposed
// anyway, so we have to create the context then.
if( xAccImpl.isValid() )
{
xAccImpl->Dispose( bRecursive );
}
else if( xParentAccImpl.isValid() )
{
// If the frame is a cell frame, the table must be notified.
// If we are in an action, a table model change event will
// be broadcasted at the end of the action to give the table
// a chance to generate a single table change event.
xParentAccImpl->DisposeChild( aFrmOrObj, bRecursive );
}
else if( xShapeAccImpl.isValid() )
{
RemoveContext( aFrmOrObj.GetSdrObject() );
xShapeAccImpl->dispose();
}
if( mpPreview && pFrm && pFrm->IsPageFrm() )
mpPreview->DisposePage( static_cast< const SwPageFrm *>( pFrm ) );
}
}
void SwAccessibleMap::InvalidatePosOrSize( const SwFrm *pFrm,
const SdrObject *pObj,
const SwRect& rOldBox )
{
SwFrmOrObj aFrmOrObj( pFrm, pObj );
if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) )
{
::vos::ORef< SwAccessibleContext > xAccImpl;
::vos::ORef< SwAccessibleContext > xParentAccImpl;
{
vos::OGuard aGuard( maMutex );
if( mpFrmMap )
{
if( aFrmOrObj.GetSwFrm() )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( aFrmOrObj.GetSwFrm() );
if( aIter != mpFrmMap->end() )
{
// If there is an accesible object already it is
// notified directly.
Reference < XAccessible > xAcc( (*aIter).second );
xAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
}
}
if( !xAccImpl.isValid() )
{
// Otherwise we look if the parent is accessible.
// If not, there is nothing to do.
const SwFrm *pParent =
SwAccessibleFrame::GetParent( aFrmOrObj,
GetShell()->IsPreView());
if( pParent )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( pParent );
if( aIter != mpFrmMap->end() )
{
Reference < XAccessible > xAcc( (*aIter).second );
xParentAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
}
}
}
}
}
if( xAccImpl.isValid() )
{
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::POS_CHANGED, xAccImpl.getBodyPtr(),
aFrmOrObj, rOldBox );
AppendEvent( aEvent );
}
else
{
xAccImpl->InvalidatePosOrSize( rOldBox );
}
}
else if( xParentAccImpl.isValid() )
{
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
xParentAccImpl.getBodyPtr(), aFrmOrObj, rOldBox );
AppendEvent( aEvent );
}
else
{
xParentAccImpl->InvalidateChildPosOrSize( aFrmOrObj,
rOldBox );
}
}
}
}
void SwAccessibleMap::InvalidateContent( const SwFrm *pFrm )
{
SwFrmOrObj aFrmOrObj( pFrm );
if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) )
{
Reference < XAccessible > xAcc;
{
vos::OGuard aGuard( maMutex );
if( mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( aFrmOrObj.GetSwFrm() );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
}
}
if( xAcc.is() )
{
SwAccessibleContext *pAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::INVALID_CONTENT, pAccImpl,
aFrmOrObj );
AppendEvent( aEvent );
}
else
{
pAccImpl->InvalidateContent();
}
}
}
}
void SwAccessibleMap::InvalidateCursorPosition( const SwFrm *pFrm )
{
SwFrmOrObj aFrmOrObj( pFrm );
sal_Bool bShapeSelected = sal_False;
const ViewShell *pVSh = GetShell();
if( pVSh->ISA( SwCrsrShell ) )
{
const SwCrsrShell *pCSh = static_cast< const SwCrsrShell * >( pVSh );
if( pCSh->IsTableMode() )
{
while( aFrmOrObj.GetSwFrm() && !aFrmOrObj.GetSwFrm()->IsCellFrm() )
aFrmOrObj = aFrmOrObj.GetSwFrm()->GetUpper();
}
else if( pVSh->ISA( SwFEShell ) )
{
sal_uInt16 nObjCount;
const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh );
const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm();
if( pFlyFrm )
{
ASSERT( !pFrm || pFrm->FindFlyFrm() == pFlyFrm,
"cursor is not contained in fly frame" );
aFrmOrObj = pFlyFrm;
}
else if( (nObjCount = pFESh->IsObjSelected()) > 0 )
{
bShapeSelected = sal_True;
aFrmOrObj = static_cast<const SwFrm *>( 0 );
}
}
}
ASSERT( bShapeSelected || aFrmOrObj.IsAccessible(GetShell()->IsPreView()),
"frame is not accessible" );
Reference < XAccessible > xOldAcc;
Reference < XAccessible > xAcc;
sal_Bool bOldShapeSelected = sal_False;
{
vos::OGuard aGuard( maMutex );
xOldAcc = mxCursorContext;
mxCursorContext = xAcc; // clear reference
bOldShapeSelected = mbShapeSelected;
mbShapeSelected = bShapeSelected;
if( aFrmOrObj.GetSwFrm() && mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( aFrmOrObj.GetSwFrm() );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
// For cells, some extra thoughts are necessary,
// because invalidating the cursor for one cell
// invalidates the cursor for all cells of the same
// table. For this reason, we don't want to
// invalidate the cursor for the old cursor object
// and the new one if they are within the same table,
// because this would result in doing the work twice.
// Moreover, we have to make sure to invalidate the
// cursor even if the current cell has no accessible object.
// If the old cursor objects exists and is in the same
// table, its the best choice, because using it avoids
// an unnessarary cursor invalidation cycle when creating
// a new object for the current cell.
if( aFrmOrObj.GetSwFrm()->IsCellFrm() )
{
if( xOldAcc.is() &&
AreInSameTable( xOldAcc, aFrmOrObj.GetSwFrm() ) )
{
if( xAcc.is() )
xOldAcc = xAcc; // avoid extra invalidation
else
xAcc = xOldAcc; // make sure ate least one
}
if( !xAcc.is() )
xAcc = GetContext( aFrmOrObj.GetSwFrm(), sal_True );
}
}
}
if( xOldAcc.is() && xOldAcc != xAcc )
InvalidateCursorPosition( xOldAcc );
if( bOldShapeSelected || bShapeSelected )
InvalidateShapeSelection();
if( xAcc.is() )
InvalidateCursorPosition( xAcc );
}
void SwAccessibleMap::InvalidateFocus()
{
Reference < XAccessible > xAcc;
sal_Bool bShapeSelected;
{
vos::OGuard aGuard( maMutex );
xAcc = mxCursorContext;
bShapeSelected = mbShapeSelected;
}
if( xAcc.is() )
{
SwAccessibleContext *pAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
pAccImpl->InvalidateFocus();
}
else if( bShapeSelected )
{
DoInvalidateShapeFocus();
}
}
void SwAccessibleMap::SetCursorContext(
const ::vos::ORef < SwAccessibleContext >& rCursorContext )
{
vos::OGuard aGuard( maMutex );
Reference < XAccessible > xAcc( rCursorContext.getBodyPtr() );
mxCursorContext = xAcc;
}
void SwAccessibleMap::InvalidateStates( sal_uInt8 nStates, const SwFrm *pFrm )
{
// Start with the frame or the first upper that is accessible
SwFrmOrObj aFrmOrObj( pFrm );
while( aFrmOrObj.GetSwFrm() &&
!aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) )
aFrmOrObj = aFrmOrObj.GetSwFrm()->GetUpper();
if( !aFrmOrObj.GetSwFrm() )
aFrmOrObj = GetShell()->GetLayout();
Reference< XAccessible > xAcc( GetContext( aFrmOrObj.GetSwFrm(), sal_True ) );
SwAccessibleContext *pAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::CARET_OR_STATES, pAccImpl,
pAccImpl->GetFrm(), nStates );
AppendEvent( aEvent );
}
else
{
pAccImpl->InvalidateStates( nStates );
}
}
void SwAccessibleMap::_InvalidateRelationSet( const SwFrm* pFrm,
sal_Bool bFrom )
{
// first, see if this frame is accessible, and if so, get the respective
SwFrmOrObj aFrmOrObj( pFrm );
if( aFrmOrObj.IsAccessible( GetShell()->IsPreView() ) )
{
Reference < XAccessible > xAcc;
Reference < XAccessible > xParentAcc;
{
vos::OGuard aGuard( maMutex );
if( mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( aFrmOrObj.GetSwFrm() );
if( aIter != mpFrmMap->end() )
{
xAcc = (*aIter).second;
}
}
}
// deliver event directly, or queue event
if( xAcc.is() )
{
SwAccessibleContext *pAccImpl =
static_cast< SwAccessibleContext *>( xAcc.get() );
if( GetShell()->ActionPend() )
{
SwAccessibleEvent_Impl aEvent(
SwAccessibleEvent_Impl::CARET_OR_STATES, pAccImpl,
pFrm, bFrom ? ACC_STATE_RELATION_FROM
: ACC_STATE_RELATION_TO );
AppendEvent( aEvent );
}
else
{
pAccImpl->InvalidateRelation( bFrom ?
AccessibleEventId::CONTENT_FLOWS_FROM_EVENT :
AccessibleEventId::CONTENT_FLOWS_TO_EVENT );
}
}
}
}
void SwAccessibleMap::InvalidateRelationSet( const SwFrm* pMaster,
const SwFrm* pFollow )
{
_InvalidateRelationSet( pMaster, sal_False );
_InvalidateRelationSet( pFollow, sal_True );
}
void SwAccessibleMap::UpdatePreview( sal_uInt8 nRow, sal_uInt8 nColumn,
sal_Int16 nStartPage,
const Size& rPageSize,
const Point& rFreePoint,
const Fraction& rScale,
sal_uInt16 nSelectedPage )
{
DBG_ASSERT( GetShell()->IsPreView(), "no preview?" );
DBG_ASSERT( mpPreview != NULL, "no preview data?" );
mpPreview->Update( nRow, nColumn, nStartPage,
rPageSize, rFreePoint, rScale, GetShell(),
nSelectedPage );
// propagate change of VisArea through the document's
// accessibility tree; this will also send appropriate scroll
// events
SwAccessibleContext* pDoc =
GetContextImpl( GetShell()->GetLayout() ).getBodyPtr();
static_cast<SwAccessibleDocumentBase*>( pDoc )->SetVisArea();
Reference < XAccessible > xOldAcc;
Reference < XAccessible > xAcc;
{
vos::OGuard aGuard( maMutex );
xOldAcc = mxCursorContext;
const SwPageFrm *pSelPage = mpPreview->GetSelPage();
if( pSelPage && mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( pSelPage );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
}
}
if( xOldAcc.is() && xOldAcc != xAcc )
InvalidateCursorPosition( xOldAcc );
if( xAcc.is() )
InvalidateCursorPosition( xAcc );
}
void SwAccessibleMap::InvalidatePreViewSelection( sal_uInt16 nSelPage )
{
DBG_ASSERT( GetShell()->IsPreView(), "no preview?" );
DBG_ASSERT( mpPreview != NULL, "no preview data?" );
mpPreview->InvalidateSelection( nSelPage );
Reference < XAccessible > xOldAcc;
Reference < XAccessible > xAcc;
{
vos::OGuard aGuard( maMutex );
xOldAcc = mxCursorContext;
const SwPageFrm *pSelPage = mpPreview->GetSelPage();
if( pSelPage && mpFrmMap )
{
SwAccessibleContextMap_Impl::iterator aIter =
mpFrmMap->find( pSelPage );
if( aIter != mpFrmMap->end() )
xAcc = (*aIter).second;
}
}
if( xOldAcc.is() && xOldAcc != xAcc )
InvalidateCursorPosition( xOldAcc );
if( xAcc.is() )
InvalidateCursorPosition( xAcc );
}
sal_Bool SwAccessibleMap::IsPageSelected( const SwPageFrm *pPageFrm ) const
{
return mpPreview && mpPreview->GetSelPage() == pPageFrm;
}
void SwAccessibleMap::FireEvents()
{
{
vos::OGuard aGuard( maEventMutex );
if( mpEvents )
{
mpEvents->SetFiring();
SwAccessibleEventList_Impl::iterator aIter = mpEvents->begin();
while( aIter != mpEvents->end() )
{
FireEvent( *aIter );
++aIter;
}
delete mpEventMap;
mpEventMap = 0;
delete mpEvents;
mpEvents = 0;
}
}
{
vos::OGuard aGuard( maMutex );
if( mpShapes )
{
delete mpShapes;
mpShapes = 0;
}
}
}
sal_Bool SwAccessibleMap::IsValid() const
{
return sal_True;
}
Rectangle SwAccessibleMap::GetVisibleArea() const
{
MapMode aSrc( MAP_TWIP );
MapMode aDest( MAP_100TH_MM );
return OutputDevice::LogicToLogic( GetVisArea().SVRect(), aSrc, aDest );
}
// Convert a MM100 value realtive to the document root into a pixel value
// realtive to the screen!
Point SwAccessibleMap::LogicToPixel( const Point& rPoint ) const
{
MapMode aSrc( MAP_100TH_MM );
MapMode aDest( MAP_TWIP );
Point aPoint = rPoint;
aPoint = OutputDevice::LogicToLogic( aPoint, aSrc, aDest );
Window *pWin = GetShell()->GetWin();
if( pWin )
{
aPoint = pWin->LogicToPixel( aPoint );
aPoint = pWin->OutputToAbsoluteScreenPixel( aPoint );
}
return aPoint;
}
Size SwAccessibleMap::LogicToPixel( const Size& rSize ) const
{
MapMode aSrc( MAP_100TH_MM );
MapMode aDest( MAP_TWIP );
Size aSize( OutputDevice::LogicToLogic( rSize, aSrc, aDest ) );
if( GetShell()->GetWin() )
{
aSize = GetShell()->GetWin()->LogicToPixel( aSize );
}
return aSize;
}
Point SwAccessibleMap::PixelToLogic( const Point& rPoint ) const
{
Point aPoint;
Window *pWin = GetShell()->GetWin();
if( pWin )
{
aPoint = pWin->ScreenToOutputPixel( rPoint );
aPoint = pWin->PixelToLogic( aPoint );
MapMode aSrc( MAP_TWIP );
MapMode aDest( MAP_100TH_MM );
aPoint = OutputDevice::LogicToLogic( aPoint, aSrc, aDest );
}
return aPoint;
}
Size SwAccessibleMap::PixelToLogic( const Size& rSize ) const
{
Size aSize;
if( GetShell()->GetWin() )
{
aSize = GetShell()->GetWin()->PixelToLogic( rSize );
MapMode aSrc( MAP_TWIP );
MapMode aDest( MAP_100TH_MM );
aSize = OutputDevice::LogicToLogic( aSize, aSrc, aDest );
}
return aSize;
}
sal_Bool SwAccessibleMap::ReplaceChild (
::accessibility::AccessibleShape* pCurrentChild,
::accessibility::AccessibleShape* pReplacement)
throw (::com::sun::star::uno::RuntimeException)
{
const SdrObject *pObj = 0;
{
vos::OGuard aGuard( maMutex );
if( mpShapeMap )
{
SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->begin();
SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->end();
while( aIter != aEndIter && !pObj )
{
Reference < XAccessible > xAcc( (*aIter).second );
::accessibility::AccessibleShape *pAccShape =
static_cast < accessibility::AccessibleShape* >( xAcc.get() );
if( pAccShape == pCurrentChild )
{
pObj = (*aIter).first;
}
++aIter;
}
}
}
if( !pObj )
return sal_False;
Dispose( 0, pObj );
{
vos::OGuard aGuard( maMutex );
if( !mpShapeMap )
mpShapeMap = new SwAccessibleShapeMap_Impl( this );
SwAccessibleShapeMap_Impl::iterator aIter =
mpShapeMap->find( pObj );
Reference < XAccessible > xAcc( pReplacement );
if( aIter != mpShapeMap->end() )
{
(*aIter).second = xAcc;
}
else
{
SwAccessibleShapeMap_Impl::value_type aEntry( pObj, xAcc );
mpShapeMap->insert( aEntry );
}
}
SwRect aEmptyRect;
InvalidatePosOrSize( 0, pObj, aEmptyRect );
return sal_True;
}
Point SwAccessibleMap::CoreToPixel( const Point& rPoint ) const
{
Point aPoint;
if( GetShell()->GetWin() )
{
PreviewAdjust( rPoint, sal_False );
aPoint = GetShell()->GetWin()->LogicToPixel( rPoint );
}
return aPoint;
}
Point SwAccessibleMap::PixelToCore( const Point& rPoint ) const
{
Point aPoint;
if( GetShell()->GetWin() )
{
PreviewAdjust( rPoint, sal_True );
aPoint = GetShell()->GetWin()->PixelToLogic( rPoint );
}
return aPoint;
}
Rectangle SwAccessibleMap::CoreToPixel( const Rectangle& rRect ) const
{
Rectangle aRect;
if( GetShell()->GetWin() )
{
PreviewAdjust( rRect.TopLeft(), sal_False );
aRect = GetShell()->GetWin()->LogicToPixel( rRect );
}
return aRect;
}
Rectangle SwAccessibleMap::PixelToCore( const Rectangle& rRect ) const
{
Rectangle aRect;
if( GetShell()->GetWin() )
{
PreviewAdjust( rRect.TopLeft(), sal_True );
aRect = GetShell()->GetWin()->PixelToLogic( rRect );
}
return aRect;
}
inline void SwAccessibleMap::PreviewAdjust( const Point& rPoint,
sal_Bool bFromPreview ) const
{
if( GetShell()->IsPreView() )
{
DBG_ASSERT( mpPreview != NULL, "need preview data" );
Window* pWin = GetShell()->GetWin();
MapMode aMode = pWin->GetMapMode();
mpPreview->AdjustMapMode( aMode, rPoint, sal_True );
pWin->SetMapMode( aMode );
}
}
//
// SwAccPreviewData
//
SwAccPreviewData::SwAccPreviewData() :
mpStartPage( 0 ),
mpSelPage( 0 ),
mnStartPage( 0 )
{
}
SwAccPreviewData::~SwAccPreviewData()
{
}
void SwAccPreviewData::Update( sal_uInt8 nRow,
sal_uInt8 nColumn,
sal_uInt16 nStartPage,
const Size& rPageSize,
const Point& rFreePixel,
const Fraction& rScale,
ViewShell* pShell,
sal_uInt16 nSelPage )
{
DBG_ASSERT( nRow > 0, "invalid row value" );
DBG_ASSERT( nColumn > 0, "invalid column value" );
DBG_ASSERT( nStartPage >= 0, "invalid start page" );
DBG_ASSERT( pShell != NULL, "need view shell" );
DBG_ASSERT( pShell->IsPreView(), "not inpreview?" );
// store the rScale (for AdjustMapMode; will be called from here, too)
maScale = rScale;
maPageSize = rPageSize;
// get first page frame from layout, and iterate to page nSttPage
SwRootFrm* pRoot = pShell->GetLayout();
DBG_ASSERT( pRoot != NULL, "No layout?" );
SwPageFrm* pPage = static_cast<SwPageFrm*>( pRoot->Lower() );
DBG_ASSERT( pPage != NULL, "No page?" );
// adjust for the first page (which is always a right page) if
// there is more than one column
sal_Bool bSkipFirstPage = (nStartPage == 0) && (nColumn != 1);
// get offset of selected page
mnStartPage = nStartPage;
nSelPage -= nStartPage;
// we'll count on nStartPage, so it should be zero-based
if( nStartPage > 0 )
nStartPage--;
// iterate until nStartPage is found
sal_Int32 nPage = 0;
while( (nStartPage > 0) && (pPage != NULL) )
{
pPage = static_cast<SwPageFrm*>( pPage->GetNext() );
nStartPage--;
// if pPage isn't valid, thethe parameter checking allowed an
// invalid index
DBG_ASSERT( pPage != NULL, "non-existing start page" );
}
// iterate over pages and collect data
// 1) VisArea as union of visible pages
// 2) areas of visible pages for preview/logic mapping
mpStartPage = pPage;
mpSelPage = 0;
if( pPage != NULL )
{
// first page: use to initialize VisArea
SwFrmOrObj aPage( pPage );
maVisArea = aPage.GetBox();
maPreviewRects.clear();
maLogicRects.clear();
// compute free point
MapMode aMapMode( MAP_TWIP );
AdjustMapMode( aMapMode );
Point aFreePoint = pShell->GetWin()->PixelToLogic( rFreePixel,
aMapMode );
// loop over col*row pages, and advance aCurrentPoint to start
// of this page's previeww
Point aCurrentPoint = aFreePoint;
for( sal_uInt8 nR = 0; (pPage != NULL) && (nR < nRow); nR++ )
{
aCurrentPoint.X() = aFreePoint.X();
for( sal_uInt8 nC = 0; (pPage != NULL) && (nC < nColumn); nC++ )
{
if( bSkipFirstPage )
{
aCurrentPoint.X() += rPageSize.Width();
bSkipFirstPage = sal_False;
// DON'T proceed to next page!
}
else
{
// collect data
aPage = pPage;
SwRect aSwRect = aPage.GetBox();
maVisArea.Union( aSwRect );
Rectangle aRect = aSwRect.SVRect();
maLogicRects.push_back( aRect );
aRect.SetPos( aCurrentPoint );
maPreviewRects.push_back( aRect );
aCurrentPoint.X() += pPage->IsEmptyPage()
? rPageSize.Width()
: aSwRect.Width();
if( 0 == nSelPage )
mpSelPage = pPage;
pPage = static_cast<SwPageFrm*>( pPage->GetNext() );
}
aCurrentPoint.X() += aFreePoint.X() +1;
nSelPage--;
}
aCurrentPoint.Y() += rPageSize.Height() + 1 + aFreePoint.Y();
}
}
}
void SwAccPreviewData::InvalidateSelection( sal_uInt16 nSelPage )
{
mpSelPage = 0;
nSelPage -= mnStartPage;
ASSERT( nSelPage >= 0, "invalid selected page" );
ASSERT( mpStartPage, "no start page" );
if( mpStartPage != NULL )
{
const SwPageFrm *pPage = mpStartPage;
// loop over col*row pages, and advance aCurrentPoint to start
// of this page's preview
while( mpSelPage == 0 && pPage != 0 )
{
if( 0 == nSelPage )
mpSelPage = pPage;
pPage = static_cast<const SwPageFrm*>( pPage->GetNext() );
nSelPage--;
}
}
ASSERT( mpSelPage, "selected page not found" );
}
struct ContainsPredicate
{
const Point& mrPoint;
ContainsPredicate( const Point& rPoint ) : mrPoint(rPoint) {}
bool operator() ( const Rectangle& rRect ) const
{
return rRect.IsInside( mrPoint ) ? true : false;
}
};
const SwRect& SwAccPreviewData::GetVisArea() const
{
return maVisArea;
}
Point SwAccPreviewData::PreviewToLogic(const Point& rPoint) const
{
Rectangles::const_iterator aIter = find_if( maPreviewRects.begin(),
maPreviewRects.end(),
ContainsPredicate( rPoint ) );
if( aIter != maPreviewRects.end() )
{
Point aPoint = rPoint;
aPoint -= aIter->TopLeft();
aPoint += (maLogicRects.begin() + ( aIter - maPreviewRects.begin() ))
->TopLeft();
return aPoint;
}
else
return Point(0,0);
}
Point SwAccPreviewData::LogicToPreview(const Point& rPoint) const
{
Rectangles::const_iterator aIter = find_if( maLogicRects.begin(),
maLogicRects.end(),
ContainsPredicate( rPoint ) );
if( aIter != maLogicRects.end() )
{
Point aPoint = rPoint;
aPoint -= aIter->TopLeft();
aPoint += (maPreviewRects.begin() + ( aIter - maLogicRects.begin() ))
->TopLeft();
return aPoint;
}
else
return Point(0,0);
}
void SwAccPreviewData::AdjustMapMode( MapMode& rMapMode ) const
{
// adjust scale
rMapMode.SetScaleX( maScale );
rMapMode.SetScaleY( maScale );
}
void SwAccPreviewData::DisposePage(const SwPageFrm *pPageFrm )
{
if( mpStartPage == pPageFrm )
mpStartPage = 0;
if( mpSelPage == pPageFrm )
mpSelPage = 0;
}
void SwAccPreviewData::AdjustMapMode( MapMode& rMapMode,
const Point& rPoint,
sal_Bool bFromPreview ) const
{
// adjust scale
AdjustMapMode( rMapMode );
// find proper rectangle
const Rectangles& rRects = bFromPreview ? maLogicRects : maPreviewRects;
Rectangles::const_iterator aBegin = rRects.begin();
Rectangles::const_iterator aEnd = rRects.end();
Rectangles::const_iterator aFound = find_if( aBegin, aEnd,
ContainsPredicate( rPoint ) );
if( aFound != aEnd )
{
// found! set new origin
Point aPoint = (maPreviewRects.begin() + (aFound - aBegin))->TopLeft();
aPoint -= (maLogicRects.begin() + (aFound-aBegin))->TopLeft();
rMapMode.SetOrigin( aPoint );
}
// else: don't adjust MapMode
}