update dev300-m58
[ooovba.git] / svx / source / accessibility / ChildrenManagerImpl.cxx
blob1655e3206a314908fe2bde1fcf01241f06581667
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ChildrenManagerImpl.cxx,v $
10 * $Revision: 1.41 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include "ChildrenManagerImpl.hxx"
35 #include <svx/ShapeTypeHandler.hxx>
36 #include <svx/AccessibleShapeInfo.hxx>
37 #ifndef _COM_SUN_STAR_ACCESSIBLE_ACCESSIBLESTATETYPE_HPP_
38 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
39 #endif
40 #include <com/sun/star/view/XSelectionSupplier.hpp>
41 #include <com/sun/star/container/XChild.hpp>
42 #include <comphelper/uno3.hxx>
43 #include <com/sun/star/container/XChild.hpp>
45 #include <rtl/ustring.hxx>
46 #include <tools/debug.hxx>
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::accessibility;
50 using ::com::sun::star::uno::Reference;
53 namespace accessibility {
55 namespace
57 void adjustIndexInParentOfShapes(ChildDescriptorListType& _rList)
59 ChildDescriptorListType::iterator aEnd = _rList.end();
60 sal_Int32 i=0;
61 for ( ChildDescriptorListType::iterator aIter = _rList.begin(); aIter != aEnd; ++aIter,++i)
62 aIter->setIndexAtAccessibleShape(i);
66 //===== AccessibleChildrenManager ===========================================
68 ChildrenManagerImpl::ChildrenManagerImpl (
69 const uno::Reference<XAccessible>& rxParent,
70 const uno::Reference<drawing::XShapes>& rxShapeList,
71 const AccessibleShapeTreeInfo& rShapeTreeInfo,
72 AccessibleContextBase& rContext)
73 : ::cppu::WeakComponentImplHelper2<
74 ::com::sun::star::document::XEventListener,
75 ::com::sun::star::view::XSelectionChangeListener>(maMutex),
76 mxShapeList (rxShapeList),
77 mxParent (rxParent),
78 maShapeTreeInfo (rShapeTreeInfo),
79 mrContext (rContext),
80 mnNewNameIndex(1),
81 mpFocusedShape(NULL)
88 ChildrenManagerImpl::~ChildrenManagerImpl (void)
90 DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose,
91 "~AccessibleDrawDocumentView: object has not been disposed");
97 void ChildrenManagerImpl::Init (void)
99 // Register as view::XSelectionChangeListener.
100 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
101 Reference<view::XSelectionSupplier> xSelectionSupplier (
102 xController, uno::UNO_QUERY);
103 if (xSelectionSupplier.is())
105 xController->addEventListener(
106 static_cast<document::XEventListener*>(this));
108 xSelectionSupplier->addSelectionChangeListener (
109 static_cast<view::XSelectionChangeListener*>(this));
112 // Register at model as document::XEventListener.
113 if (maShapeTreeInfo.GetModelBroadcaster().is())
114 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
115 static_cast<document::XEventListener*>(this));
121 long ChildrenManagerImpl::GetChildCount (void) const throw ()
123 return maVisibleChildren.size();
129 /** Return the requested accessible child object. Create it if it is not
130 yet in the cache.
132 uno::Reference<XAccessible>
133 ChildrenManagerImpl::GetChild (long nIndex)
134 throw (::com::sun::star::uno::RuntimeException,
135 ::com::sun::star::lang::IndexOutOfBoundsException)
137 // Check wether the given index is valid.
138 if (nIndex < 0 || (unsigned long)nIndex >= maVisibleChildren.size())
139 throw lang::IndexOutOfBoundsException (
140 ::rtl::OUString::createFromAscii(
141 "no accessible child with index ") + nIndex,
142 mxParent);
144 return GetChild (maVisibleChildren[nIndex],nIndex);
150 /** Return the requested accessible child object. Create it if it is not
151 yet in the cache.
153 uno::Reference<XAccessible>
154 ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex)
155 throw (::com::sun::star::uno::RuntimeException)
157 if ( ! rChildDescriptor.mxAccessibleShape.is())
159 ::osl::MutexGuard aGuard (maMutex);
160 // Make sure that the requested accessible object has not been
161 // created while locking the global mutex.
162 if ( ! rChildDescriptor.mxAccessibleShape.is())
164 AccessibleShapeInfo aShapeInfo(
165 rChildDescriptor.mxShape,
166 mxParent,
167 this,
168 mnNewNameIndex++);
169 // Create accessible object that corresponds to the descriptor's
170 // shape.
171 AccessibleShape* pShape =
172 ShapeTypeHandler::Instance().CreateAccessibleObject (
173 aShapeInfo,
174 maShapeTreeInfo);
175 rChildDescriptor.mxAccessibleShape = uno::Reference<XAccessible> (
176 static_cast<uno::XWeak*>(pShape),
177 uno::UNO_QUERY);
178 // Now that there is a reference to the new accessible shape we
179 // can safely call its Init() method.
180 if ( pShape != NULL )
182 pShape->Init();
183 pShape->setIndexInParent(_nIndex);
188 return rChildDescriptor.mxAccessibleShape;
194 uno::Reference<XAccessible>
195 ChildrenManagerImpl::GetChild (const uno::Reference<drawing::XShape>& xShape)
196 throw (uno::RuntimeException)
198 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
199 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
201 if ( I->mxShape.get() == xShape.get() )
202 return I->mxAccessibleShape;
204 return uno::Reference<XAccessible> ();
210 /** Find all shapes among the specified shapes that lie fully or partially
211 inside the visible area. Put those shapes into the cleared cache. The
212 corresponding accessible objects will be created on demand.
214 At the moment, first all accessible objects are removed from the cache
215 and the appropriate listeners are informed of this. Next, the list is
216 created again. This should be optimized in the future to not remove and
217 create objects that will be in the list before and after the update
218 method.
220 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand)
222 if (maShapeTreeInfo.GetViewForwarder() == NULL)
223 return;
224 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
226 // 1. Create a local list of visible shapes.
227 ChildDescriptorListType aChildList;
228 CreateListOfVisibleShapes (aChildList);
230 // 2. Merge the information that is already known about the visible
231 // shapes from the current list into the new list.
232 MergeAccessibilityInformation (aChildList);
234 // 3. Replace the current list of visible shapes with the new one. Do
235 // the same with the visible area.
237 ::osl::MutexGuard aGuard (maMutex);
238 adjustIndexInParentOfShapes(aChildList);
240 // Use swap to copy the contents of the new list in constant time.
241 maVisibleChildren.swap (aChildList);
243 // aChildList now contains all the old children, while maVisibleChildren
244 // contains all the current children
246 // 4. Find all shapes in the old list that are not in the current list,
247 // send appropriate events and remove the accessible shape.
249 // Do this *after* we have set our new list of children, because
250 // removing a child may cause
252 // ChildDescriptor::disposeAccessibleObject -->
253 // AccessibleContextBase::CommitChange -->
254 // AtkListener::notifyEvent ->
255 // AtkListener::handleChildRemoved ->
256 // AtkListener::updateChildList
257 // AccessibleDrawDocumentView::getAccessibleChildCount ->
258 // ChildrenManagerImpl::GetChildCount ->
259 // maVisibleChildren.size()
261 // to be fired, and so the operations will take place on
262 // the list we are trying to replace
264 RemoveNonVisibleChildren (maVisibleChildren, aChildList);
266 aChildList.clear();
268 maVisibleArea = aVisibleArea;
271 // 5. If the visible area has changed then send events that signal a
272 // change of their bounding boxes for all shapes that are members of
273 // both the current and the new list of visible shapes.
274 if (maVisibleArea != aVisibleArea)
275 SendVisibleAreaEvents (maVisibleChildren);
277 // 6. If children have to be created immediately and not on demand then
278 // create the missing accessible objects now.
279 if ( ! bCreateNewObjectsOnDemand)
280 CreateAccessibilityObjects (maVisibleChildren);
286 void ChildrenManagerImpl::CreateListOfVisibleShapes (
287 ChildDescriptorListType& raDescriptorList)
289 ::osl::MutexGuard aGuard (maMutex);
291 OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != NULL);
293 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
295 // Add the visible shapes for wich the accessible objects already exist.
296 AccessibleShapeList::iterator I,aEnd = maAccessibleShapes.end();
297 for (I=maAccessibleShapes.begin(); I != aEnd; ++I)
299 if (I->is())
301 uno::Reference<XAccessibleComponent> xComponent (
302 (*I)->getAccessibleContext(), uno::UNO_QUERY);
303 if (xComponent.is())
305 // The bounding box of the object already is clipped to the
306 // visible area. The object is therefore visible if the
307 // bounding box has non-zero extensions.
308 awt::Rectangle aPixelBBox (xComponent->getBounds());
309 if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
310 raDescriptorList.push_back (ChildDescriptor (*I));
315 // Add the visible shapes for which only the XShapes exist.
316 uno::Reference<container::XIndexAccess> xShapeAccess (mxShapeList, uno::UNO_QUERY);
317 if (xShapeAccess.is())
319 sal_Int32 nShapeCount = xShapeAccess->getCount();
320 raDescriptorList.reserve( nShapeCount );
321 awt::Point aPos;
322 awt::Size aSize;
323 Rectangle aBoundingBox;
324 uno::Reference<drawing::XShape> xShape;
325 for (sal_Int32 i=0; i<nShapeCount; ++i)
327 xShapeAccess->getByIndex(i) >>= xShape;
328 aPos = xShape->getPosition();
329 aSize = xShape->getSize();
331 aBoundingBox.nLeft = aPos.X;
332 aBoundingBox.nTop = aPos.Y;
333 aBoundingBox.nRight = aPos.X + aSize.Width;
334 aBoundingBox.nBottom = aPos.Y + aSize.Height;
336 // Insert shape if it is visible, i.e. its bounding box overlaps
337 // the visible area.
338 if ( aBoundingBox.IsOver (aVisibleArea) )
339 raDescriptorList.push_back (ChildDescriptor (xShape));
347 void ChildrenManagerImpl::RemoveNonVisibleChildren (
348 const ChildDescriptorListType& rNewChildList,
349 ChildDescriptorListType& rOldChildList)
351 // Iterate over list of formerly visible children and remove those that
352 // are not visible anymore, i.e. member of the new list of visible
353 // children.
354 ChildDescriptorListType::iterator I, aEnd = rOldChildList.end();
355 for (I=rOldChildList.begin(); I != aEnd; ++I)
357 if (::std::find(rNewChildList.begin(), rNewChildList.end(), *I) == rNewChildList.end())
359 // The child is disposed when there is a UNO shape from which
360 // the accessible shape can be created when the shape becomes
361 // visible again. When there is no such UNO shape then simply
362 // reset the descriptor but keep the accessibility object.
363 if (I->mxShape.is())
365 UnregisterAsDisposeListener (I->mxShape);
366 I->disposeAccessibleObject (mrContext);
368 else
370 AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
371 pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
372 I->mxAccessibleShape = NULL;
381 void ChildrenManagerImpl::MergeAccessibilityInformation (
382 ChildDescriptorListType& raNewChildList)
384 ChildDescriptorListType::iterator aOldChildDescriptor;
385 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end();
386 for (I=raNewChildList.begin(); I != aEnd; ++I)
388 aOldChildDescriptor = ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), *I);
390 // Copy accessible shape if that exists in the old descriptor.
391 bool bRegistrationIsNecessary = true;
392 if (aOldChildDescriptor != maVisibleChildren.end())
393 if (aOldChildDescriptor->mxAccessibleShape.is())
395 I->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
396 I->mbCreateEventPending = false;
397 bRegistrationIsNecessary = false;
399 if (bRegistrationIsNecessary)
400 RegisterAsDisposeListener (I->mxShape);
407 void ChildrenManagerImpl::SendVisibleAreaEvents (
408 ChildDescriptorListType& raNewChildList)
410 ChildDescriptorListType::iterator I,aEnd = raNewChildList.end();
411 for (I=raNewChildList.begin(); I != aEnd; ++I)
413 // Tell shape of changed visible area. To do this, fake a
414 // change of the view forwarder. (Actually we usually get here
415 // as a result of a change of the view forwarder).
416 AccessibleShape* pShape = I->GetAccessibleShape ();
417 if (pShape != NULL)
418 pShape->ViewForwarderChanged (
419 IAccessibleViewForwarderListener::VISIBLE_AREA,
420 maShapeTreeInfo.GetViewForwarder());
427 void ChildrenManagerImpl::CreateAccessibilityObjects (
428 ChildDescriptorListType& raNewChildList)
430 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end();
431 sal_Int32 nPos = 0;
432 for ( I = raNewChildList.begin(); I != aEnd; ++I,++nPos)
434 // Create the associated accessible object when the flag says so and
435 // it does not yet exist.
436 if ( ! I->mxAccessibleShape.is() )
437 GetChild (*I,nPos);
438 if (I->mxAccessibleShape.is() && I->mbCreateEventPending)
440 I->mbCreateEventPending = false;
441 mrContext.CommitChange (
442 AccessibleEventId::CHILD,
443 uno::makeAny(I->mxAccessibleShape),
444 uno::Any());
452 void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
454 if (rxShape.is())
456 ::osl::ClearableMutexGuard aGuard (maMutex);
458 // Test visibility of the shape.
459 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
460 awt::Point aPos = rxShape->getPosition();
461 awt::Size aSize = rxShape->getSize();
463 Rectangle aBoundingBox (
464 aPos.X,
465 aPos.Y,
466 aPos.X + aSize.Width,
467 aPos.Y + aSize.Height);
469 // Add the shape only when it belongs to the list of shapes stored
470 // in mxShapeList (which is either a page or a group shape).
471 Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
472 if (xChild.is())
474 Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
475 if (xParent == mxShapeList)
476 if (aBoundingBox.IsOver (aVisibleArea))
478 // Add shape to list of visible shapes.
479 maVisibleChildren.push_back (ChildDescriptor (rxShape));
481 // Create accessibility object.
482 ChildDescriptor& rDescriptor = maVisibleChildren.back();
483 GetChild (rDescriptor, maVisibleChildren.size()-1);
485 // Inform listeners about new child.
486 uno::Any aNewShape;
487 aNewShape <<= rDescriptor.mxAccessibleShape;
488 aGuard.clear();
489 mrContext.CommitChange (
490 AccessibleEventId::CHILD,
491 aNewShape,
492 uno::Any());
493 RegisterAsDisposeListener (rDescriptor.mxShape);
502 void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
504 if (rxShape.is())
506 ::osl::ClearableMutexGuard aGuard (maMutex);
508 // Search shape in list of visible children.
509 ChildDescriptorListType::iterator I (
510 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
511 ChildDescriptor (rxShape)));
512 if (I != maVisibleChildren.end())
514 // Remove descriptor from that list.
515 Reference<XAccessible> xAccessibleShape (I->mxAccessibleShape);
517 UnregisterAsDisposeListener (I->mxShape);
518 // Dispose the accessible object.
519 I->disposeAccessibleObject (mrContext);
521 // Now we can safely remove the child descriptor and thus
522 // invalidate the iterator.
523 maVisibleChildren.erase (I);
525 adjustIndexInParentOfShapes(maVisibleChildren);
533 void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference<
534 ::com::sun::star::drawing::XShapes>& xShapeList)
536 mxShapeList = xShapeList;
542 void ChildrenManagerImpl::AddAccessibleShape (std::auto_ptr<AccessibleShape> pShape)
544 if (pShape.get() != NULL)
545 maAccessibleShapes.push_back (pShape.release());
551 void ChildrenManagerImpl::ClearAccessibleShapeList (void)
553 // Copy the list of (visible) shapes to local lists and clear the
554 // originals.
555 ChildDescriptorListType aLocalVisibleChildren;
556 aLocalVisibleChildren.swap(maVisibleChildren);
557 AccessibleShapeList aLocalAccessibleShapes;
558 aLocalAccessibleShapes.swap(maAccessibleShapes);
560 // Tell the listeners that all children are gone.
561 mrContext.CommitChange (
562 AccessibleEventId::INVALIDATE_ALL_CHILDREN,
563 uno::Any(),
564 uno::Any());
566 // There are no accessible shapes left so the index assigned to new
567 // accessible shapes can be reset.
568 mnNewNameIndex = 1;
570 // Now the objects in the local lists can be safely disposed without
571 // having problems with callers that want to update their child lists.
573 // Clear the list of visible accessible objects. Objects not created on
574 // demand for XShapes are treated below.
575 ChildDescriptorListType::iterator I,aEnd = aLocalVisibleChildren.end();
576 for (I=aLocalVisibleChildren.begin(); I != aEnd; ++I)
577 if ( I->mxAccessibleShape.is() && I->mxShape.is() )
579 ::comphelper::disposeComponent(I->mxAccessibleShape);
580 I->mxAccessibleShape = NULL;
583 // Dispose all objects in the accessible shape list.
584 AccessibleShapeList::iterator J,aEnd2 = aLocalAccessibleShapes.end();
585 for (J=aLocalAccessibleShapes.begin(); J != aEnd2; ++J)
586 if (J->is())
588 // Dispose the object.
589 ::comphelper::disposeComponent(*J);
590 *J = NULL;
597 /** If the broadcasters change at which this object is registered then
598 unregister at old and register at new broadcasters.
600 void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo)
602 // Remember the current broadcasters and exchange the shape tree info.
603 Reference<document::XEventBroadcaster> xCurrentBroadcaster;
604 Reference<frame::XController> xCurrentController;
605 Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
607 ::osl::MutexGuard aGuard (maMutex);
608 xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
609 xCurrentController = maShapeTreeInfo.GetController();
610 xCurrentSelectionSupplier = Reference<view::XSelectionSupplier> (
611 xCurrentController, uno::UNO_QUERY);
612 maShapeTreeInfo = rShapeTreeInfo;
615 // Move registration to new model.
616 if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
618 // Register at new broadcaster.
619 if (maShapeTreeInfo.GetModelBroadcaster().is())
620 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
621 static_cast<document::XEventListener*>(this));
623 // Unregister at old broadcaster.
624 if (xCurrentBroadcaster.is())
625 xCurrentBroadcaster->removeEventListener (
626 static_cast<document::XEventListener*>(this));
629 // Move registration to new selection supplier.
630 Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
631 Reference<view::XSelectionSupplier> xNewSelectionSupplier (
632 xNewController, uno::UNO_QUERY);
633 if (xNewSelectionSupplier != xCurrentSelectionSupplier)
635 // Register at new broadcaster.
636 if (xNewSelectionSupplier.is())
638 xNewController->addEventListener(
639 static_cast<document::XEventListener*>(this));
641 xNewSelectionSupplier->addSelectionChangeListener (
642 static_cast<view::XSelectionChangeListener*>(this));
645 // Unregister at old broadcaster.
646 if (xCurrentSelectionSupplier.is())
648 xCurrentSelectionSupplier->removeSelectionChangeListener (
649 static_cast<view::XSelectionChangeListener*>(this));
651 xCurrentController->removeEventListener(
652 static_cast<document::XEventListener*>(this));
660 //===== lang::XEventListener ================================================
662 void SAL_CALL
663 ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
664 throw (uno::RuntimeException)
666 if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
667 || rEventObject.Source == maShapeTreeInfo.GetController())
669 impl_dispose();
672 // Handle disposing UNO shapes.
673 else
675 Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
677 // Find the descriptor for the given shape.
678 ChildDescriptorListType::iterator I (
679 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
680 ChildDescriptor (xShape)));
681 if (I != maVisibleChildren.end())
683 // Clear the descriptor.
684 I->disposeAccessibleObject (mrContext);
685 I->mxShape = NULL;
693 //===== document::XEventListener ============================================
695 /** Listen for new and removed shapes.
697 void SAL_CALL
698 ChildrenManagerImpl::notifyEvent (
699 const document::EventObject& rEventObject)
700 throw (uno::RuntimeException)
702 static const ::rtl::OUString sShapeInserted (
703 RTL_CONSTASCII_USTRINGPARAM("ShapeInserted"));
704 static const ::rtl::OUString sShapeRemoved (
705 RTL_CONSTASCII_USTRINGPARAM("ShapeRemoved"));
708 if (rEventObject.EventName.equals (sShapeInserted))
709 AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
710 else if (rEventObject.EventName.equals (sShapeRemoved))
711 RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
712 // else ignore unknown event.
718 //===== view::XSelectionChangeListener ======================================
720 void SAL_CALL
721 ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/)
722 throw (uno::RuntimeException)
724 UpdateSelection ();
730 void ChildrenManagerImpl::impl_dispose (void)
732 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
733 // Remove from broadcasters.
736 Reference<view::XSelectionSupplier> xSelectionSupplier (
737 xController, uno::UNO_QUERY);
738 if (xSelectionSupplier.is())
740 xSelectionSupplier->removeSelectionChangeListener (
741 static_cast<view::XSelectionChangeListener*>(this));
744 catch( uno::RuntimeException&)
749 if (xController.is())
750 xController->removeEventListener(
751 static_cast<document::XEventListener*>(this));
753 catch( uno::RuntimeException&)
756 maShapeTreeInfo.SetController (NULL);
760 // Remove from broadcaster.
761 if (maShapeTreeInfo.GetModelBroadcaster().is())
762 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
763 static_cast<document::XEventListener*>(this));
764 maShapeTreeInfo.SetModelBroadcaster (NULL);
766 catch( uno::RuntimeException& )
769 ClearAccessibleShapeList ();
770 SetShapeList (NULL);
775 void SAL_CALL ChildrenManagerImpl::disposing (void)
777 impl_dispose();
783 // This method is experimental. Use with care.
784 long int ChildrenManagerImpl::GetChildIndex (const ::com::sun::star::uno::Reference<
785 ::com::sun::star::accessibility::XAccessible>& xChild) const
786 throw (::com::sun::star::uno::RuntimeException)
788 ::osl::MutexGuard aGuard (maMutex);
789 sal_Int32 nCount = maVisibleChildren.size();
790 for (sal_Int32 i=0; i < nCount; ++i)
792 // Is this equality comparison valid?
793 if (maVisibleChildren[i].mxAccessibleShape == xChild)
794 return i;
797 return -1;
803 //===== IAccessibleViewForwarderListener ====================================
805 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType,
806 const IAccessibleViewForwarder* pViewForwarder)
808 if (aChangeType == IAccessibleViewForwarderListener::VISIBLE_AREA)
809 Update (false);
810 else
812 ::osl::MutexGuard aGuard (maMutex);
813 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
814 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
816 AccessibleShape* pShape = I->GetAccessibleShape();
817 if (pShape != NULL)
818 pShape->ViewForwarderChanged (aChangeType, pViewForwarder);
826 //===== IAccessibleParent ===================================================
828 sal_Bool ChildrenManagerImpl::ReplaceChild (
829 AccessibleShape* pCurrentChild,
830 const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape,
831 const long _nIndex,
832 const AccessibleShapeTreeInfo& _rShapeTreeInfo)
833 throw (uno::RuntimeException)
835 AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this, _nIndex );
836 // create the new child
837 AccessibleShape* pNewChild = ShapeTypeHandler::Instance().CreateAccessibleObject (
838 aShapeInfo,
839 _rShapeTreeInfo
841 Reference< XAccessible > xNewChild( pNewChild ); // keep this alive (do this before calling Init!)
842 if ( pNewChild )
843 pNewChild->Init();
845 sal_Bool bResult = sal_False;
847 // Iterate over the visible children. If one of them has an already
848 // created accessible object that matches pCurrentChild then replace
849 // it. Otherwise the child to replace is either not in the list or has
850 // not ye been created (and is therefore not in the list, too) and a
851 // replacement is not necessary.
852 ChildDescriptorListType::iterator I,aEnd = maVisibleChildren.end();
853 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
855 if (I->GetAccessibleShape() == pCurrentChild)
857 // Dispose the current child and send an event about its deletion.
858 pCurrentChild->dispose();
859 mrContext.CommitChange (
860 AccessibleEventId::CHILD,
861 uno::Any(),
862 uno::makeAny (I->mxAccessibleShape));
864 // Replace with replacement and send an event about existance
865 // of the new child.
866 I->mxAccessibleShape = pNewChild;
867 mrContext.CommitChange (
868 AccessibleEventId::CHILD,
869 uno::makeAny (I->mxAccessibleShape),
870 uno::Any());
871 bResult = sal_True;
872 break;
876 // When not found among the visible children we have to search the list
877 // of accessible shapes. This is not yet implemented.
879 return bResult;
885 /** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
886 of all visible children. Maybe this should be changed to all children.
888 Iterate over all descriptors of visible accessible shapes and look them
889 up in the selection.
891 If there is no valid controller then all shapes are deselected and
892 unfocused. If the controller's frame is not active then all shapes are
893 unfocused.
895 void ChildrenManagerImpl::UpdateSelection (void)
897 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
898 Reference<view::XSelectionSupplier> xSelectionSupplier (
899 xController, uno::UNO_QUERY);
901 // Try to cast the selection both to a multi selection and to a single
902 // selection.
903 Reference<container::XIndexAccess> xSelectedShapeAccess;
904 Reference<drawing::XShape> xSelectedShape;
905 if (xSelectionSupplier.is())
907 xSelectedShapeAccess = Reference<container::XIndexAccess> (
908 xSelectionSupplier->getSelection(), uno::UNO_QUERY);
909 xSelectedShape = Reference<drawing::XShape> (
910 xSelectionSupplier->getSelection(), uno::UNO_QUERY);
913 // Remember the current and new focused shape.
914 AccessibleShape* pCurrentlyFocusedShape = NULL;
915 AccessibleShape* pNewFocusedShape = NULL;
917 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
918 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
920 AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
921 if (I->mxAccessibleShape.is() && I->mxShape.is() && pAccessibleShape!=NULL)
923 bool bShapeIsSelected = false;
925 // Look up the shape in the (single or multi-) selection.
926 if (xSelectedShape.is())
928 if (I->mxShape == xSelectedShape)
930 bShapeIsSelected = true;
931 pNewFocusedShape = pAccessibleShape;
934 else if (xSelectedShapeAccess.is())
936 sal_Int32 nCount=xSelectedShapeAccess->getCount();
937 for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
938 if (xSelectedShapeAccess->getByIndex(i) == I->mxShape)
940 bShapeIsSelected = true;
941 // In a multi-selection no shape has the focus.
942 if (nCount == 1)
943 pNewFocusedShape = pAccessibleShape;
947 // Set or reset the SELECTED state.
948 if (bShapeIsSelected)
949 pAccessibleShape->SetState (AccessibleStateType::SELECTED);
950 else
951 pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
953 // Does the shape have the current selection?
954 if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
955 pCurrentlyFocusedShape = pAccessibleShape;
959 // Check if the frame we are in is currently active. If not then make
960 // sure to not send a FOCUSED state change.
961 if (xController.is())
963 Reference<frame::XFrame> xFrame (xController->getFrame());
964 if (xFrame.is())
965 if ( ! xFrame->isActive())
966 pNewFocusedShape = NULL;
969 // Move focus from current to newly focused shape.
970 if (pCurrentlyFocusedShape != pNewFocusedShape)
972 if (pCurrentlyFocusedShape != NULL)
973 pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
974 if (pNewFocusedShape != NULL)
975 pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
978 // Remember whether there is a shape that now has the focus.
979 mpFocusedShape = pNewFocusedShape;
985 bool ChildrenManagerImpl::HasFocus (void)
987 return mpFocusedShape != NULL;
993 void ChildrenManagerImpl::RemoveFocus (void)
995 if (mpFocusedShape != NULL)
997 mpFocusedShape->ResetState (AccessibleStateType::FOCUSED);
998 mpFocusedShape = NULL;
1004 void ChildrenManagerImpl::RegisterAsDisposeListener (
1005 const Reference<drawing::XShape>& xShape)
1007 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1008 if (xComponent.is())
1009 xComponent->addEventListener (
1010 static_cast<document::XEventListener*>(this));
1016 void ChildrenManagerImpl::UnregisterAsDisposeListener (
1017 const Reference<drawing::XShape>& xShape)
1019 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1020 if (xComponent.is())
1021 xComponent->removeEventListener (
1022 static_cast<document::XEventListener*>(this));
1028 //===== AccessibleChildDescriptor ===========================================
1030 ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
1031 : mxShape (xShape),
1032 mxAccessibleShape (NULL),
1033 mbCreateEventPending (true)
1035 // Empty.
1041 ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
1042 : mxShape (NULL),
1043 mxAccessibleShape (rxAccessibleShape),
1044 mbCreateEventPending (true)
1046 // Make sure that the accessible object has the <const>VISIBLE</const>
1047 // state set.
1048 AccessibleShape* pAccessibleShape = GetAccessibleShape();
1049 pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
1055 ChildDescriptor::~ChildDescriptor (void)
1062 AccessibleShape* ChildDescriptor::GetAccessibleShape (void) const
1064 return static_cast<AccessibleShape*> (mxAccessibleShape.get());
1066 // -----------------------------------------------------------------------------
1067 void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex)
1069 AccessibleShape* pShape = GetAccessibleShape();
1070 if ( pShape )
1071 pShape->setIndexInParent(_nIndex);
1073 // -----------------------------------------------------------------------------
1078 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent)
1080 if (mxAccessibleShape.is())
1082 // Send event that the shape has been removed.
1083 uno::Any aOldValue;
1084 aOldValue <<= mxAccessibleShape;
1085 rParent.CommitChange (
1086 AccessibleEventId::CHILD,
1087 uno::Any(),
1088 aOldValue);
1090 // Dispose and remove the object.
1091 Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY);
1092 if (xComponent.is())
1093 xComponent->dispose ();
1095 mxAccessibleShape = NULL;
1100 } // end of namespace accessibility