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 $
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>
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
{
57 void adjustIndexInParentOfShapes(ChildDescriptorListType
& _rList
)
59 ChildDescriptorListType::iterator aEnd
= _rList
.end();
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
),
78 maShapeTreeInfo (rShapeTreeInfo
),
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
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
,
144 return GetChild (maVisibleChildren
[nIndex
],nIndex
);
150 /** Return the requested accessible child object. Create it if it is not
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
,
169 // Create accessible object that corresponds to the descriptor's
171 AccessibleShape
* pShape
=
172 ShapeTypeHandler::Instance().CreateAccessibleObject (
175 rChildDescriptor
.mxAccessibleShape
= uno::Reference
<XAccessible
> (
176 static_cast<uno::XWeak
*>(pShape
),
178 // Now that there is a reference to the new accessible shape we
179 // can safely call its Init() method.
180 if ( pShape
!= NULL
)
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
220 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand
)
222 if (maShapeTreeInfo
.GetViewForwarder() == NULL
)
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
);
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
)
301 uno::Reference
<XAccessibleComponent
> xComponent (
302 (*I
)->getAccessibleContext(), uno::UNO_QUERY
);
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
);
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
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
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.
365 UnregisterAsDisposeListener (I
->mxShape
);
366 I
->disposeAccessibleObject (mrContext
);
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 ();
418 pShape
->ViewForwarderChanged (
419 IAccessibleViewForwarderListener::VISIBLE_AREA
,
420 maShapeTreeInfo
.GetViewForwarder());
427 void ChildrenManagerImpl::CreateAccessibilityObjects (
428 ChildDescriptorListType
& raNewChildList
)
430 ChildDescriptorListType::iterator I
, aEnd
= raNewChildList
.end();
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() )
438 if (I
->mxAccessibleShape
.is() && I
->mbCreateEventPending
)
440 I
->mbCreateEventPending
= false;
441 mrContext
.CommitChange (
442 AccessibleEventId::CHILD
,
443 uno::makeAny(I
->mxAccessibleShape
),
452 void ChildrenManagerImpl::AddShape (const Reference
<drawing::XShape
>& rxShape
)
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 (
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
);
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.
487 aNewShape
<<= rDescriptor
.mxAccessibleShape
;
489 mrContext
.CommitChange (
490 AccessibleEventId::CHILD
,
493 RegisterAsDisposeListener (rDescriptor
.mxShape
);
502 void ChildrenManagerImpl::RemoveShape (const Reference
<drawing::XShape
>& rxShape
)
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
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
,
566 // There are no accessible shapes left so the index assigned to new
567 // accessible shapes can be reset.
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
)
588 // Dispose the object.
589 ::comphelper::disposeComponent(*J
);
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 ================================================
663 ChildrenManagerImpl::disposing (const lang::EventObject
& rEventObject
)
664 throw (uno::RuntimeException
)
666 if (rEventObject
.Source
== maShapeTreeInfo
.GetModelBroadcaster()
667 || rEventObject
.Source
== maShapeTreeInfo
.GetController())
672 // Handle disposing UNO shapes.
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
);
693 //===== document::XEventListener ============================================
695 /** Listen for new and removed shapes.
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 ======================================
721 ChildrenManagerImpl::selectionChanged (const lang::EventObject
& /*rEvent*/)
722 throw (uno::RuntimeException
)
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 ();
775 void SAL_CALL
ChildrenManagerImpl::disposing (void)
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
)
803 //===== IAccessibleViewForwarderListener ====================================
805 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType
,
806 const IAccessibleViewForwarder
* pViewForwarder
)
808 if (aChangeType
== IAccessibleViewForwarderListener::VISIBLE_AREA
)
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();
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
,
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 (
841 Reference
< XAccessible
> xNewChild( pNewChild
); // keep this alive (do this before calling 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
,
862 uno::makeAny (I
->mxAccessibleShape
));
864 // Replace with replacement and send an event about existance
866 I
->mxAccessibleShape
= pNewChild
;
867 mrContext
.CommitChange (
868 AccessibleEventId::CHILD
,
869 uno::makeAny (I
->mxAccessibleShape
),
876 // When not found among the visible children we have to search the list
877 // of accessible shapes. This is not yet implemented.
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
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
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
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.
943 pNewFocusedShape
= pAccessibleShape
;
947 // Set or reset the SELECTED state.
948 if (bShapeIsSelected
)
949 pAccessibleShape
->SetState (AccessibleStateType::SELECTED
);
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());
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
)
1032 mxAccessibleShape (NULL
),
1033 mbCreateEventPending (true)
1041 ChildDescriptor::ChildDescriptor (const Reference
<XAccessible
>& rxAccessibleShape
)
1043 mxAccessibleShape (rxAccessibleShape
),
1044 mbCreateEventPending (true)
1046 // Make sure that the accessible object has the <const>VISIBLE</const>
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();
1071 pShape
->setIndexInParent(_nIndex
);
1073 // -----------------------------------------------------------------------------
1078 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase
& rParent
)
1080 if (mxAccessibleShape
.is())
1082 // Send event that the shape has been removed.
1084 aOldValue
<<= mxAccessibleShape
;
1085 rParent
.CommitChange (
1086 AccessibleEventId::CHILD
,
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