Files
libreoffice/svx/source/accessibility/ChildrenManagerImpl.cxx

912 lines
30 KiB
C++
Raw Normal View History

2002-04-11 11:59:54 +00:00
/*************************************************************************
*
* $RCSfile: ChildrenManagerImpl.cxx,v $
*
* $Revision: 1.22 $
2002-04-11 11:59:54 +00:00
*
* last change: $Author: fs $ $Date: 2002-09-23 09:01:26 $
2002-04-11 11:59:54 +00:00
*
* 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): _______________________________________
*
*
************************************************************************/
#include "ChildrenManagerImpl.hxx"
#ifndef _SVX_ACCESSIBILITY_SHAPE_TYPE_HANDLER_HXX
#include "ShapeTypeHandler.hxx"
#endif
#ifndef _SVX_ACCESSIBILITY_ACCESSIBLE_SHAPE_INFO_HXX
#include "AccessibleShapeInfo.hxx"
#endif
2002-05-17 15:11:41 +00:00
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBLE_ACCESSIBLESTATETYPE_HPP_
#include <drafts/com/sun/star/accessibility/AccessibleStateType.hpp>
#endif
#ifndef _COM_SUN_STAR_VIEW_XSELECTIONSUPPLIER_HPP_
#include <com/sun/star/view/XSelectionSupplier.hpp>
#endif
2002-04-11 11:59:54 +00:00
#include <rtl/ustring.hxx>
2002-06-12 11:56:26 +00:00
#include <tools/debug.hxx>
2002-04-11 11:59:54 +00:00
using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::drafts::com::sun::star::accessibility;
using ::com::sun::star::uno::Reference;
2002-04-11 11:59:54 +00:00
namespace accessibility {
//===== AccessibleChildrenManager ===========================================
ChildrenManagerImpl::ChildrenManagerImpl (
const uno::Reference<XAccessible>& rxParent,
const uno::Reference<drawing::XShapes>& rxShapeList,
const AccessibleShapeTreeInfo& rShapeTreeInfo,
2002-04-11 11:59:54 +00:00
AccessibleContextBase& rContext)
2002-06-12 11:56:26 +00:00
: ::cppu::WeakComponentImplHelper2<
::com::sun::star::document::XEventListener,
::com::sun::star::view::XSelectionChangeListener>(maMutex),
mxShapeList (rxShapeList),
2002-04-11 11:59:54 +00:00
mxParent (rxParent),
maShapeTreeInfo (rShapeTreeInfo),
2002-04-11 11:59:54 +00:00
mrContext (rContext)
{
OSL_TRACE ("creating new children manager with %d children", rxShapeList->getCount());
}
ChildrenManagerImpl::~ChildrenManagerImpl (void)
{
2002-06-12 11:56:26 +00:00
DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose,
"~AccessibleDrawDocumentView: object has not been disposed");
2002-04-11 11:59:54 +00:00
}
void ChildrenManagerImpl::Init (void)
{
// Register as view::XSelectionChangeListener.
Reference<view::XSelectionSupplier> xSelectionSupplier (
maShapeTreeInfo.GetController(), uno::UNO_QUERY);
if (xSelectionSupplier.is())
xSelectionSupplier->addSelectionChangeListener (
static_cast<view::XSelectionChangeListener*>(this));
// Register at model as document::XEventListener.
if (maShapeTreeInfo.GetModelBroadcaster().is())
maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
static_cast<document::XEventListener*>(this));
2002-04-11 11:59:54 +00:00
}
long ChildrenManagerImpl::GetChildCount (void) const throw ()
{
return maVisibleChildren.size();
}
/** Return the requested accessible child object. Create it if it is not
yet in the cache.
*/
uno::Reference<XAccessible>
ChildrenManagerImpl::GetChild (long nIndex)
throw (::com::sun::star::uno::RuntimeException)
{
// Check wether the given index is valid.
if (nIndex < 0 || (unsigned long)nIndex >= maVisibleChildren.size())
throw lang::IndexOutOfBoundsException (
::rtl::OUString::createFromAscii(
"no accessible child with index ") + nIndex,
2002-04-11 11:59:54 +00:00
mxParent);
return GetChild (maVisibleChildren[nIndex]);
}
/** Return the requested accessible child object. Create it if it is not
yet in the cache.
*/
uno::Reference<XAccessible>
ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor)
2002-04-11 11:59:54 +00:00
throw (::com::sun::star::uno::RuntimeException)
{
if ( ! rChildDescriptor.mxAccessibleShape.is())
{
2002-06-12 11:56:26 +00:00
::osl::MutexGuard aGuard (maMutex);
2002-04-11 11:59:54 +00:00
// Make sure that the requested accessible object has not been
// created while locking the global mutex.
if ( ! rChildDescriptor.mxAccessibleShape.is())
{
// Create accessible object that corresponds to the descriptor's
// shape.
AccessibleShape* pShape =
ShapeTypeHandler::Instance().CreateAccessibleObject (
AccessibleShapeInfo (
rChildDescriptor.mxShape,
mxParent,
this),
maShapeTreeInfo);
2002-04-11 11:59:54 +00:00
rChildDescriptor.mxAccessibleShape = uno::Reference<XAccessible> (
static_cast<uno::XWeak*>(pShape),
uno::UNO_QUERY);
// Now that there is a reference to the new accessible shape we
// can safely call its Init() method.
if (pShape != NULL)
pShape->Init();
2002-04-11 11:59:54 +00:00
}
}
2002-04-11 11:59:54 +00:00
return rChildDescriptor.mxAccessibleShape;
}
uno::Reference<XAccessible>
ChildrenManagerImpl::GetChild (const uno::Reference<drawing::XShape>& xShape)
throw (uno::RuntimeException)
{
ChildDescriptorListType::iterator I;
for (I=maVisibleChildren.begin(); I!=maVisibleChildren.end(); I++)
{
if (I->mxShape == xShape)
return I->mxAccessibleShape;
}
return uno::Reference<XAccessible> ();
}
/** Find all shapes among the specified shapes that lie fully or partially
inside the visible area. Put those shapes into the cleared cache. The
corresponding accessible objects will be created on demand.
At the moment, first all accessible objects are removed from the cache
and the appropriate listeners are informed of this. Next, the list is
created again. This should be optimized in the future to not remove and
create objects that will be in the list before and after the update
method.
*/
void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand)
{
if (maShapeTreeInfo.GetViewForwarder() == NULL)
return;
Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
{
2002-04-11 11:59:54 +00:00
OSL_TRACE ("ChildrenManagerImpl::update called with VisibleArea = %d %d %d %d",
aVisibleArea.getX(), aVisibleArea.getY(),
aVisibleArea.getWidth(), aVisibleArea.getHeight());
OSL_TRACE (" shape list contains %d children",
mxShapeList.is()?mxShapeList->getCount():0);
}
2002-04-11 11:59:54 +00:00
// 1. Create a local list of visible shapes.
ChildDescriptorListType aNewChildList;
CreateListOfVisibleShapes (aNewChildList);
// 2. Find all shapes in the current list that are not in the new list,
// send appropriate events and remove the accessible shape.
RemoveNonVisibleChildren (aNewChildList);
// 3. Merge the information that is already known about the visible
// shapes from the current list into the new list.
MergeAccessibilityInformation (aNewChildList);
// 4. If the visible area has changed then send events that signal a
// change of their bounding boxes for all shapes that are members of
// both the current and the new list of visible shapes.
if (maVisibleArea != aVisibleArea)
SendVisibleAreaEvents (aNewChildList);
// 5. If children have to be created immediately and not on demand then
2002-04-11 11:59:54 +00:00
// create the missing accessible objects now.
if ( ! bCreateNewObjectsOnDemand)
CreateAccessibilityObjects (aNewChildList);
// 6. Replace the current list of visible shapes with the new one. Do
// the same with the visible area.
2002-06-12 11:56:26 +00:00
::osl::MutexGuard aGuard (maMutex);
2002-04-11 11:59:54 +00:00
maVisibleChildren = aNewChildList;
maVisibleArea = aVisibleArea;
}
void ChildrenManagerImpl::CreateListOfVisibleShapes (
ChildDescriptorListType& raDescriptorList)
{
2002-06-12 11:56:26 +00:00
::osl::MutexGuard aGuard (maMutex);
2002-04-11 11:59:54 +00:00
OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != NULL);
Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
2002-04-11 11:59:54 +00:00
// Add the visible shapes for wich the accessible objects already exist.
AccessibleShapeList::iterator I;
2002-04-11 11:59:54 +00:00
for (I=maAccessibleShapes.begin(); I!=maAccessibleShapes.end(); ++I)
{
if (I->is())
{
uno::Reference<XAccessibleComponent> xComponent (
(*I)->getAccessibleContext(), uno::UNO_QUERY);
if (xComponent.is())
{
// The bounding box of the object already is clipped to the
// visible area. The object is therefore visible if the
// bounding box has non-zero extensions.
awt::Rectangle aPixelBBox (xComponent->getBounds());
if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
raDescriptorList.push_back (ChildDescriptor (*I));
else
OSL_TRACE ("accessible shape %x not visible", *I);
}
}
2002-04-11 11:59:54 +00:00
}
// Add the visible shapes for which only the XShapes exist.
2002-04-11 11:59:54 +00:00
uno::Reference<container::XIndexAccess> xShapeAccess (mxShapeList, uno::UNO_QUERY);
if (xShapeAccess.is())
{
sal_Int32 nShapeCount = xShapeAccess->getCount();
for (sal_Int32 i=0; i<nShapeCount; i++)
{
uno::Reference<drawing::XShape> xShape;
xShapeAccess->getByIndex(i) >>= xShape;
Rectangle aBoundingBox (
xShape->getPosition().X,
xShape->getPosition().Y,
2002-04-15 14:14:29 +00:00
xShape->getPosition().X + xShape->getSize().Width,
xShape->getPosition().Y + xShape->getSize().Height);
2002-04-11 11:59:54 +00:00
// Insert shape if it is visible, i.e. its bounding box overlaps
// the visible area.
if (aBoundingBox.IsOver (aVisibleArea))
raDescriptorList.push_back (ChildDescriptor (xShape));
else
OSL_TRACE ("shape %x not visible", xShape);
2002-04-11 11:59:54 +00:00
}
}
}
void ChildrenManagerImpl::RemoveNonVisibleChildren (
ChildDescriptorListType& raNewChildList)
{
// Iterate over list of formerly visible children and remove those that
// are not visible anymore, i.e. member of the new list of visible
// children.
2002-04-11 11:59:54 +00:00
ChildDescriptorListType::iterator I;
for (I=maVisibleChildren.begin(); I!=maVisibleChildren.end(); I++)
{
if (find (raNewChildList.begin(), raNewChildList.end(), *I) == raNewChildList.end())
{
2002-04-15 14:14:29 +00:00
OSL_TRACE ("child no longer visible");
2002-04-11 11:59:54 +00:00
if (I->mxAccessibleShape.is())
{
// Send event that the shape has been removed.
2002-04-15 14:14:29 +00:00
uno::Any aOldValue;
2002-04-11 11:59:54 +00:00
aOldValue <<= I->mxAccessibleShape;
mrContext.CommitChange (
AccessibleEventId::ACCESSIBLE_CHILD_EVENT,
2002-04-15 14:14:29 +00:00
uno::Any(),
2002-04-11 11:59:54 +00:00
aOldValue);
// Dispose and remove the object.
if (I->mxShape.is())
{
Reference<lang::XComponent> xComponent (I->mxAccessibleShape, uno::UNO_QUERY);
xComponent->dispose ();
I->mxAccessibleShape = NULL;
}
2002-04-11 11:59:54 +00:00
}
}
}
}
void ChildrenManagerImpl::MergeAccessibilityInformation (
ChildDescriptorListType& raNewChildList)
{
ChildDescriptorListType::iterator aOldChildDescriptor;
ChildDescriptorListType::iterator I;
for (I=raNewChildList.begin(); I!=raNewChildList.end(); I++)
{
aOldChildDescriptor = find (maVisibleChildren.begin(), maVisibleChildren.end(), *I);
// Copy accessible shape if that exists in the old descriptor.
if (aOldChildDescriptor != maVisibleChildren.end())
if (aOldChildDescriptor->mxAccessibleShape.is())
{
I->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
// I->mpAccessibleShape = aOldChildDescriptor->mpAccessibleShape;
2002-04-15 14:14:29 +00:00
I->mbCreateEventPending = false;
2002-04-11 11:59:54 +00:00
}
}
}
void ChildrenManagerImpl::SendVisibleAreaEvents (
ChildDescriptorListType& raNewChildList)
{
ChildDescriptorListType::iterator I;
for (I=raNewChildList.begin(); I!=raNewChildList.end(); I++)
{
// Tell shape of changed visible area. To do this, fake a
// change of the view forwarder. (Actually we usually get here
// as a result of a change of the view forwarder).
AccessibleShape* pShape = I->GetAccessibleShape ();
if (pShape != NULL)
pShape->ViewForwarderChanged (
2002-04-11 11:59:54 +00:00
IAccessibleViewForwarderListener::VISIBLE_AREA,
maShapeTreeInfo.GetViewForwarder());
2002-04-11 11:59:54 +00:00
}
}
void ChildrenManagerImpl::CreateAccessibilityObjects (
ChildDescriptorListType& raNewChildList)
{
OSL_TRACE ("sending events for new shape");
2002-04-11 11:59:54 +00:00
ChildDescriptorListType::iterator I;
for (I=raNewChildList.begin(); I!=raNewChildList.end(); I++)
{
// Create the associated accessible object when the flag says so and
// it does not yet exist.
if ( ! I->mxAccessibleShape.is())
2002-04-15 14:14:29 +00:00
GetChild (*I);
if (I->mxAccessibleShape.is() && I->mbCreateEventPending)
{
uno::Any aNewShape;
aNewShape <<= I->mxAccessibleShape;
mrContext.CommitChange (
AccessibleEventId::ACCESSIBLE_CHILD_EVENT,
aNewShape,
uno::Any());
}
2002-04-11 11:59:54 +00:00
}
OSL_TRACE ("done sending events for new shape");
2002-04-11 11:59:54 +00:00
}
void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference<
::com::sun::star::drawing::XShapes>& xShapeList)
{
mxShapeList = xShapeList;
}
void ChildrenManagerImpl::AddAccessibleShape (std::auto_ptr<AccessibleShape> pShape)
2002-04-11 11:59:54 +00:00
{
if (pShape.get() != NULL)
maAccessibleShapes.push_back (pShape.release());
2002-04-11 11:59:54 +00:00
}
void ChildrenManagerImpl::ClearAccessibleShapeList (void)
{
// Clear the list of visible accessible objects. Objects not created on
// demand for XShapes are treated below.
2002-04-15 14:14:29 +00:00
ChildDescriptorListType::iterator I;
for (I=maVisibleChildren.begin(); I!=maVisibleChildren.end(); I++)
if (I->mxAccessibleShape.is() && I->mxShape.is())
2002-04-15 14:14:29 +00:00
{
uno::Any aShape;
aShape <<= I->mxAccessibleShape;
mrContext.CommitChange (
AccessibleEventId::ACCESSIBLE_CHILD_EVENT,
uno::Any(),
aShape);
// Dispose the object.
Reference<lang::XComponent> xComponent (
I->mxAccessibleShape, uno::UNO_QUERY);
if (xComponent.is())
xComponent->dispose ();
// Reset the reference to the accessible object in any case. If
// it has not been disposed above it will be soon.
I->mxAccessibleShape = NULL;
2002-04-15 14:14:29 +00:00
}
maVisibleChildren.clear ();
// Dispose all objects in the accessible shape list.
AccessibleShapeList::iterator J;
for (J=maAccessibleShapes.begin(); J!=maAccessibleShapes.end(); J++)
if (J->is())
{
mrContext.CommitChange (
AccessibleEventId::ACCESSIBLE_CHILD_EVENT,
uno::Any(),
uno::makeAny (*J));
// Dispose the object.
Reference<lang::XComponent> xComponent (*J, uno::UNO_QUERY);
if (xComponent.is())
xComponent->dispose ();
}
maAccessibleShapes.clear ();
2002-04-11 11:59:54 +00:00
}
/** If the broadcasters change at which this object is registered then
unregister at old and register at new broadcasters.
*/
void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo)
2002-04-11 11:59:54 +00:00
{
// Remember the current broadcasters and exchange the shape tree info.
Reference<document::XEventBroadcaster> xCurrentBroadcaster;
Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
2002-04-11 11:59:54 +00:00
{
2002-06-12 11:56:26 +00:00
::osl::MutexGuard aGuard (maMutex);
xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
xCurrentSelectionSupplier = Reference<view::XSelectionSupplier> (
maShapeTreeInfo.GetController(), uno::UNO_QUERY);
maShapeTreeInfo = rShapeTreeInfo;
2002-04-11 11:59:54 +00:00
}
// Move registration to new model.
if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
2002-04-15 14:14:29 +00:00
{
// Register at new broadcaster.
if (maShapeTreeInfo.GetModelBroadcaster().is())
maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
2002-04-15 14:14:29 +00:00
static_cast<document::XEventListener*>(this));
// Unregister at old broadcaster.
if (xCurrentBroadcaster.is())
xCurrentBroadcaster->removeEventListener (
static_cast<document::XEventListener*>(this));
}
// Move registration to new selection supplier.
Reference<view::XSelectionSupplier> xNewSelectionSupplier (
maShapeTreeInfo.GetController(), uno::UNO_QUERY);
if (xNewSelectionSupplier != xCurrentSelectionSupplier)
{
// Register at new broadcaster.
if (xNewSelectionSupplier.is())
xNewSelectionSupplier->addSelectionChangeListener (
static_cast<view::XSelectionChangeListener*>(this));
// Unregister at old broadcaster.
if (xCurrentSelectionSupplier.is())
xCurrentSelectionSupplier->removeSelectionChangeListener (
static_cast<view::XSelectionChangeListener*>(this));
}
2002-04-11 11:59:54 +00:00
}
//===== lang::XEventListener ================================================
void SAL_CALL
ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
throw (uno::RuntimeException)
{
if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster())
{
maShapeTreeInfo.SetModelBroadcaster (NULL);
2002-04-29 12:08:30 +00:00
// The disposing of a model should be handled elsewhere. But to be
// on the safe side we remove all of our children.
ClearAccessibleShapeList ();
SetShapeList (NULL);
}
else if (rEventObject.Source
== Reference<view::XSelectionSupplier> (
maShapeTreeInfo.GetController(), uno::UNO_QUERY))
{
maShapeTreeInfo.SetController (NULL);
}
2002-04-11 11:59:54 +00:00
}
//===== document::XEventListener ============================================
/** Listen for new and removed shapes.
*/
2002-04-11 11:59:54 +00:00
void SAL_CALL
ChildrenManagerImpl::notifyEvent (
const document::EventObject& rEventObject)
2002-04-11 11:59:54 +00:00
throw (uno::RuntimeException)
{
static const OUString sShapeInserted (
RTL_CONSTASCII_USTRINGPARAM("ShapeInserted"));
static const OUString sShapeRemoved (
RTL_CONSTASCII_USTRINGPARAM("ShapeRemoved"));
#ifdef DBG_UTIL
OSL_TRACE ("ChildrenManagerImpl::notifyEvent %s",
::rtl::OUStringToOString(
rEventObject.EventName,RTL_TEXTENCODING_ASCII_US).getStr());
#endif
if (rEventObject.EventName.equals (sShapeInserted)
|| rEventObject.EventName.equals (sShapeRemoved))
2002-04-11 11:59:54 +00:00
{
// A child may have been added or removed. Call Update() to
// make the change visible.
Update (false);
UpdateSelection ();
2002-04-11 11:59:54 +00:00
}
}
//===== view::XSelectionChangeListener ======================================
void SAL_CALL
ChildrenManagerImpl::selectionChanged (const lang::EventObject& rEvent)
throw (uno::RuntimeException)
{
OSL_TRACE ("selection changed");
UpdateSelection ();
}
2002-06-12 11:56:26 +00:00
void SAL_CALL ChildrenManagerImpl::disposing (void)
{
OSL_TRACE ("ChildrenManagerImpl::disposing()");
// Remove from broadcasters.
Reference<view::XSelectionSupplier> xSelectionSupplier (
maShapeTreeInfo.GetController(), uno::UNO_QUERY);
if (xSelectionSupplier.is())
xSelectionSupplier->removeSelectionChangeListener (
static_cast<view::XSelectionChangeListener*>(this));
if (maShapeTreeInfo.GetModelBroadcaster().is())
maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
static_cast<document::XEventListener*>(this));
ClearAccessibleShapeList ();
}
2002-04-11 11:59:54 +00:00
// This method is experimental. Use with care.
long int ChildrenManagerImpl::GetChildIndex (const ::com::sun::star::uno::Reference<
::drafts::com::sun::star::accessibility::XAccessible>& xChild) const
throw (::com::sun::star::uno::RuntimeException)
{
2002-06-12 11:56:26 +00:00
::osl::MutexGuard aGuard (maMutex);
for (unsigned long i=0; i<maVisibleChildren.size(); i++)
2002-04-11 11:59:54 +00:00
{
// Is this equality comparison valid?
if (maVisibleChildren[i].mxAccessibleShape == xChild)
return i;
}
return -1;
}
//===== IAccessibleViewForwarderListener ====================================
2002-04-11 11:59:54 +00:00
void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType,
const IAccessibleViewForwarder* pViewForwarder)
{
if (aChangeType == IAccessibleViewForwarderListener::VISIBLE_AREA)
2002-04-15 14:14:29 +00:00
Update (false);
2002-04-11 11:59:54 +00:00
else
{
2002-06-12 11:56:26 +00:00
::osl::MutexGuard aGuard (maMutex);
for (unsigned long i=0; i<maVisibleChildren.size(); i++)
{
AccessibleShape* pShape = maVisibleChildren[i].GetAccessibleShape();
if (pShape != NULL)
pShape->ViewForwarderChanged (aChangeType, pViewForwarder);
}
2002-04-11 11:59:54 +00:00
}
}
//===== IAccessibleParent ===================================================
sal_Bool ChildrenManagerImpl::ReplaceChild (
AccessibleShape* pCurrentChild,
const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape,
const long _nIndex,
const AccessibleShapeTreeInfo& _rShapeTreeInfo)
throw (uno::RuntimeException)
{
// create the new child
AccessibleShape* pNewChild = ShapeTypeHandler::Instance().CreateAccessibleObject (
AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this, _nIndex ),
_rShapeTreeInfo
);
sal_Bool bResult = sal_False;
// Iterate over the visible children. If one of them has an already
// created accessible object that matches pCurrentChild then replace
// it. Otherwise the child to replace is either not in the list or has
// not ye been created (and is therefore not in the list, too) and a
// replacement is not necessary.
ChildDescriptorListType::iterator I;
for (I=maVisibleChildren.begin(); I!=maVisibleChildren.end(); I++)
{
if (I->GetAccessibleShape() == pCurrentChild)
{
// Dispose the current child and send an event about its deletion.
pCurrentChild->dispose();
mrContext.CommitChange (
AccessibleEventId::ACCESSIBLE_CHILD_EVENT,
uno::Any(),
uno::makeAny (I->mxAccessibleShape));
// Replace with replacement and send an event about existance
// of the new child.
I->mxAccessibleShape = pNewChild;
mrContext.CommitChange (
AccessibleEventId::ACCESSIBLE_CHILD_EVENT,
uno::makeAny (I->mxAccessibleShape),
uno::Any());
bResult = sal_True;
break;
}
}
// When not found among the visible children we have to search the list
// of accessible shapes. This is not yet implemented.
return bResult;
}
/** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
of all visible children. Maybe this should be changed to all children.
2002-05-17 15:11:41 +00:00
Iterate over all descriptors of visible accessible shapes and look them
up in the selection.
If there is no valid controller then all shapes are deselected and
unfocused. If the controller's frame is not active then all shapes are
unfocused.
2002-05-17 15:11:41 +00:00
*/
void ChildrenManagerImpl::UpdateSelection (void)
{
OSL_TRACE ("ChildrenManagerImpl::UpdateSelection");
Reference<frame::XController> xController(maShapeTreeInfo.GetController());
Reference<view::XSelectionSupplier> xSelectionSupplier (
xController, uno::UNO_QUERY);
2002-05-17 15:11:41 +00:00
// Try to cast the selection both to a multi selection and to a single
// selection.
Reference<container::XIndexAccess> xSelectedShapeAccess;
Reference<drawing::XShape> xSelectedShape;
if (xSelectionSupplier.is())
{
xSelectedShapeAccess = Reference<container::XIndexAccess> (
xSelectionSupplier->getSelection(), uno::UNO_QUERY);
xSelectedShape = Reference<drawing::XShape> (
xSelectionSupplier->getSelection(), uno::UNO_QUERY);
}
2002-05-17 15:11:41 +00:00
// Remember the current and new focused shape.
AccessibleShape* pCurrentlyFocusedShape = NULL;
AccessibleShape* pNewFocusedShape = NULL;
ChildDescriptorListType::iterator I;
OSL_TRACE (" there are %d visible children", maVisibleChildren.size());
2002-05-17 15:11:41 +00:00
for (I=maVisibleChildren.begin(); I!=maVisibleChildren.end(); I++)
{
OSL_TRACE (" looking for visible shape");
2002-05-17 15:11:41 +00:00
AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
if (I->mxAccessibleShape.is() && I->mxShape.is() && pAccessibleShape!=NULL)
{
bool bShapeIsSelected = false;
OSL_TRACE (" shape exists");
2002-05-17 15:11:41 +00:00
// Look up the shape in the (single or multi-) selection.
2002-05-17 15:11:41 +00:00
if (xSelectedShape.is())
{
OSL_TRACE (" comparing to single selected shape.");
if (I->mxShape == xSelectedShape)
{
bShapeIsSelected = true;
2002-05-17 15:11:41 +00:00
pNewFocusedShape = pAccessibleShape;
}
2002-05-17 15:11:41 +00:00
}
else if (xSelectedShapeAccess.is())
{
OSL_TRACE (" comparing to multiple selected shapes.");
2002-05-17 15:11:41 +00:00
for (sal_Int32 i=0,nCount=xSelectedShapeAccess->getCount(); i<nCount&&!bShapeIsSelected; i++)
if (xSelectedShapeAccess->getByIndex(i) == I->mxShape)
{
bShapeIsSelected = true;
// In a multi-selection no shape has the focus.
2002-05-17 15:11:41 +00:00
if (nCount == 1)
pNewFocusedShape = pAccessibleShape;
}
}
OSL_TRACE (" new selection state is %d", bShapeIsSelected?1:0);
2002-05-17 15:11:41 +00:00
// Set or reset the SELECTED state.
if (bShapeIsSelected)
pAccessibleShape->SetState (AccessibleStateType::SELECTED);
else
pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
// Does the shape have the current selection?
if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
pCurrentlyFocusedShape = pAccessibleShape;
}
}
// Check if the frame we are in is currently active. If not then make
// sure to not send a FOCUSED state change.
if (xController.is())
{
Reference<frame::XFrame> xFrame (xController->getFrame());
if (xFrame.is())
if ( ! xFrame->isActive())
pNewFocusedShape = NULL;
}
// Move focus from current to newly focused shape.
if (pCurrentlyFocusedShape != pNewFocusedShape)
{
if (pCurrentlyFocusedShape != NULL)
pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
if (pNewFocusedShape != NULL)
pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
}
2002-05-17 15:11:41 +00:00
}
2002-04-11 11:59:54 +00:00
//===== AccessibleChildDescriptor ===========================================
ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
2002-04-11 11:59:54 +00:00
: mxShape (xShape),
mxAccessibleShape (NULL),
2002-04-15 14:14:29 +00:00
mbCreateEventPending (true)
2002-04-11 11:59:54 +00:00
{
// Empty.
}
ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
2002-04-11 11:59:54 +00:00
: mxShape (NULL),
mxAccessibleShape (rxAccessibleShape),
2002-04-15 14:14:29 +00:00
mbCreateEventPending (true)
2002-04-11 11:59:54 +00:00
{
// Empty.
}
AccessibleShape* ChildDescriptor::GetAccessibleShape (void) const
{
return static_cast<AccessibleShape*> (mxAccessibleShape.get());
}
2002-04-11 11:59:54 +00:00
/** Compare two child descriptors. Take into account that a child
descriptor may be based on a UNO shape or, already, on an accessible
shape.
*/
bool ChildDescriptor::operator == (const ChildDescriptor& aDescriptor)
{
if (mxShape == aDescriptor.mxShape)
if (mxShape.is())
return true;
else if (mxAccessibleShape == aDescriptor.mxAccessibleShape)
return true;
return false;
}
/** The ordering defined by this operator is only used in order to be able
to put child descriptors in some STL containers. The ordering itself is
not so important, its 'features' are not used.
*/
bool ChildDescriptor::operator < (const ChildDescriptor& aDescriptor)
{
2002-06-12 11:56:26 +00:00
if (mxShape < aDescriptor.mxShape)
return true;
else
return false;
}
2002-04-11 11:59:54 +00:00
} // end of namespace accessibility