1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
24 #include "ChildrenManagerImpl.hxx"
25 #include <svx/ShapeTypeHandler.hxx>
26 #include <svx/AccessibleShapeInfo.hxx>
27 #include <vcl/svapp.hxx>
28 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
29 #include <com/sun/star/view/XSelectionSupplier.hpp>
30 #include <com/sun/star/container/XChild.hpp>
31 #include <comphelper/uno3.hxx>
33 #include <rtl/ustring.hxx>
34 #include <tools/debug.hxx>
35 #include <svx/SvxShapeTypes.hxx>
36 #include <vcl/window.hxx>
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::accessibility
;
40 using ::com::sun::star::uno::Reference
;
42 namespace accessibility
{
46 void adjustIndexInParentOfShapes(ChildDescriptorListType
& _rList
)
48 ChildDescriptorListType::iterator aEnd
= _rList
.end();
50 for ( ChildDescriptorListType::iterator aIter
= _rList
.begin(); aIter
!= aEnd
; ++aIter
,++i
)
51 aIter
->setIndexAtAccessibleShape(i
);
55 // AccessibleChildrenManager
56 ChildrenManagerImpl::ChildrenManagerImpl (
57 const uno::Reference
<XAccessible
>& rxParent
,
58 const uno::Reference
<drawing::XShapes
>& rxShapeList
,
59 const AccessibleShapeTreeInfo
& rShapeTreeInfo
,
60 AccessibleContextBase
& rContext
)
61 : ::cppu::WeakComponentImplHelper2
<
62 ::com::sun::star::document::XEventListener
,
63 ::com::sun::star::view::XSelectionChangeListener
>(maMutex
),
64 mxShapeList (rxShapeList
),
66 maShapeTreeInfo (rShapeTreeInfo
),
76 ChildrenManagerImpl::~ChildrenManagerImpl()
78 DBG_ASSERT (rBHelper
.bDisposed
|| rBHelper
.bInDispose
,
79 "~AccessibleDrawDocumentView: object has not been disposed");
85 void ChildrenManagerImpl::Init()
87 // Register as view::XSelectionChangeListener.
88 Reference
<frame::XController
> xController(maShapeTreeInfo
.GetController());
89 Reference
<view::XSelectionSupplier
> xSelectionSupplier (
90 xController
, uno::UNO_QUERY
);
91 if (xSelectionSupplier
.is())
93 xController
->addEventListener(
94 static_cast<document::XEventListener
*>(this));
96 xSelectionSupplier
->addSelectionChangeListener (
97 static_cast<view::XSelectionChangeListener
*>(this));
100 // Register at model as document::XEventListener.
101 if (maShapeTreeInfo
.GetModelBroadcaster().is())
102 maShapeTreeInfo
.GetModelBroadcaster()->addEventListener (
103 static_cast<document::XEventListener
*>(this));
109 long ChildrenManagerImpl::GetChildCount() const throw ()
111 return maVisibleChildren
.size();
115 ::com::sun::star::uno::Reference
<
116 ::com::sun::star::drawing::XShape
> ChildrenManagerImpl::GetChildShape(long nIndex
)
117 throw (::com::sun::star::uno::RuntimeException
,
118 ::com::sun::star::lang::IndexOutOfBoundsException
)
120 uno::Reference
<XAccessible
> xAcc
= GetChild(nIndex
);
121 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
122 for (I
= maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
124 if (I
->mxAccessibleShape
== xAcc
)
127 return uno::Reference
< drawing::XShape
> ();
130 /** Return the requested accessible child object. Create it if it is not
133 uno::Reference
<XAccessible
>
134 ChildrenManagerImpl::GetChild (long nIndex
)
135 throw (::com::sun::star::uno::RuntimeException
,
136 ::com::sun::star::lang::IndexOutOfBoundsException
)
138 // Check whether the given index is valid.
139 if (nIndex
< 0 || (unsigned long)nIndex
>= maVisibleChildren
.size())
140 throw lang::IndexOutOfBoundsException (
141 "no accessible child with index " + OUString::number(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())
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.
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
)
281 //operate on a copy of the list and restore it afterwards to guard
282 //against the pathological case where maVisibleChildren gets modified
283 //by other calls to this object while CreateAccessibilityObjects
284 //executes which can happen when java is disabled and the "enable-java"
285 //dialog appears during the instantiation of the linguistic components
286 //triggered by the creation of shapes belonging to the a11y objects
288 //i.e. launch start-center, launch impress with java disabled and
289 //a java-using linguistic component installed
290 maVisibleChildren
.swap(aChildList
);
291 CreateAccessibilityObjects(aChildList
);
292 maVisibleChildren
.swap(aChildList
);
296 void ChildrenManagerImpl::CreateListOfVisibleShapes (
297 ChildDescriptorListType
& raDescriptorList
)
301 OSL_ASSERT (maShapeTreeInfo
.GetViewForwarder() != NULL
);
303 Rectangle aVisibleArea
= maShapeTreeInfo
.GetViewForwarder()->GetVisibleArea();
305 // Add the visible shapes for which the accessible objects already exist.
306 AccessibleShapeList::iterator I
,aEnd
= maAccessibleShapes
.end();
307 for (I
=maAccessibleShapes
.begin(); I
!= aEnd
; ++I
)
311 uno::Reference
<XAccessibleComponent
> xComponent (
312 (*I
)->getAccessibleContext(), uno::UNO_QUERY
);
315 // The bounding box of the object already is clipped to the
316 // visible area. The object is therefore visible if the
317 // bounding box has non-zero extensions.
318 awt::Rectangle
aPixelBBox (xComponent
->getBounds());
319 if ((aPixelBBox
.Width
> 0) && (aPixelBBox
.Height
> 0))
320 raDescriptorList
.push_back (ChildDescriptor (*I
));
325 // Add the visible shapes for which only the XShapes exist.
326 uno::Reference
<container::XIndexAccess
> xShapeAccess (mxShapeList
, uno::UNO_QUERY
);
327 if (xShapeAccess
.is())
329 sal_Int32 nShapeCount
= xShapeAccess
->getCount();
330 raDescriptorList
.reserve( nShapeCount
);
333 Rectangle aBoundingBox
;
334 uno::Reference
<drawing::XShape
> xShape
;
335 for (sal_Int32 i
=0; i
<nShapeCount
; ++i
)
337 xShapeAccess
->getByIndex(i
) >>= xShape
;
338 aPos
= xShape
->getPosition();
339 aSize
= xShape
->getSize();
341 aBoundingBox
.Left() = aPos
.X
;
342 aBoundingBox
.Top() = aPos
.Y
;
343 aBoundingBox
.Right() = aPos
.X
+ aSize
.Width
;
344 aBoundingBox
.Bottom() = aPos
.Y
+ aSize
.Height
;
346 // Insert shape if it is visible, i.e. its bounding box overlaps
348 if ( aBoundingBox
.IsOver (aVisibleArea
) )
349 raDescriptorList
.push_back (ChildDescriptor (xShape
));
357 void ChildrenManagerImpl::RemoveNonVisibleChildren (
358 const ChildDescriptorListType
& rNewChildList
,
359 ChildDescriptorListType
& rOldChildList
)
361 // Iterate over list of formerly visible children and remove those that
362 // are not visible anymore, i.e. member of the new list of visible
364 ChildDescriptorListType::iterator I
, aEnd
= rOldChildList
.end();
365 for (I
=rOldChildList
.begin(); I
!= aEnd
; ++I
)
367 if (::std::find(rNewChildList
.begin(), rNewChildList
.end(), *I
) == rNewChildList
.end())
369 // The child is disposed when there is a UNO shape from which
370 // the accessible shape can be created when the shape becomes
371 // visible again. When there is no such UNO shape then simply
372 // reset the descriptor but keep the accessibility object.
375 UnregisterAsDisposeListener (I
->mxShape
);
376 I
->disposeAccessibleObject (mrContext
);
380 AccessibleShape
* pAccessibleShape
= I
->GetAccessibleShape();
381 pAccessibleShape
->ResetState (AccessibleStateType::VISIBLE
);
382 I
->mxAccessibleShape
= NULL
;
391 void ChildrenManagerImpl::MergeAccessibilityInformation (
392 ChildDescriptorListType
& raNewChildList
)
394 ChildDescriptorListType::iterator aOldChildDescriptor
;
395 ChildDescriptorListType::iterator I
, aEnd
= raNewChildList
.end();
396 for (I
=raNewChildList
.begin(); I
!= aEnd
; ++I
)
398 aOldChildDescriptor
= ::std::find (maVisibleChildren
.begin(), maVisibleChildren
.end(), *I
);
400 // Copy accessible shape if that exists in the old descriptor.
401 bool bRegistrationIsNecessary
= true;
402 if (aOldChildDescriptor
!= maVisibleChildren
.end())
403 if (aOldChildDescriptor
->mxAccessibleShape
.is())
405 I
->mxAccessibleShape
= aOldChildDescriptor
->mxAccessibleShape
;
406 I
->mbCreateEventPending
= false;
407 bRegistrationIsNecessary
= false;
409 if (bRegistrationIsNecessary
)
410 RegisterAsDisposeListener (I
->mxShape
);
417 void ChildrenManagerImpl::SendVisibleAreaEvents (
418 ChildDescriptorListType
& raNewChildList
)
420 ChildDescriptorListType::iterator I
,aEnd
= raNewChildList
.end();
421 for (I
=raNewChildList
.begin(); I
!= aEnd
; ++I
)
423 // Tell shape of changed visible area. To do this, fake a
424 // change of the view forwarder. (Actually we usually get here
425 // as a result of a change of the view forwarder).
426 AccessibleShape
* pShape
= I
->GetAccessibleShape ();
428 pShape
->ViewForwarderChanged (
429 IAccessibleViewForwarderListener::VISIBLE_AREA
,
430 maShapeTreeInfo
.GetViewForwarder());
437 void ChildrenManagerImpl::CreateAccessibilityObjects (
438 ChildDescriptorListType
& raNewChildList
)
440 ChildDescriptorListType::iterator I
, aEnd
= raNewChildList
.end();
442 for ( I
= raNewChildList
.begin(); I
!= aEnd
; ++I
,++nPos
)
444 // Create the associated accessible object when the flag says so and
445 // it does not yet exist.
446 if ( ! I
->mxAccessibleShape
.is() )
448 if (I
->mxAccessibleShape
.is() && I
->mbCreateEventPending
)
450 I
->mbCreateEventPending
= false;
451 mrContext
.CommitChange (
452 AccessibleEventId::CHILD
,
453 uno::makeAny(I
->mxAccessibleShape
),
462 void ChildrenManagerImpl::AddShape (const Reference
<drawing::XShape
>& rxShape
)
466 SolarMutexClearableGuard aGuard
;
468 // Test visibility of the shape.
469 Rectangle aVisibleArea
= maShapeTreeInfo
.GetViewForwarder()->GetVisibleArea();
470 awt::Point aPos
= rxShape
->getPosition();
471 awt::Size aSize
= rxShape
->getSize();
473 Rectangle
aBoundingBox (
476 aPos
.X
+ aSize
.Width
,
477 aPos
.Y
+ aSize
.Height
);
479 // Add the shape only when it belongs to the list of shapes stored
480 // in mxShapeList (which is either a page or a group shape).
481 Reference
<container::XChild
> xChild (rxShape
, uno::UNO_QUERY
);
484 Reference
<drawing::XShapes
> xParent (xChild
->getParent(), uno::UNO_QUERY
);
485 if (xParent
== mxShapeList
)
486 if (aBoundingBox
.IsOver (aVisibleArea
))
488 // Add shape to list of visible shapes.
489 maVisibleChildren
.push_back (ChildDescriptor (rxShape
));
491 // Create accessibility object.
492 ChildDescriptor
& rDescriptor
= maVisibleChildren
.back();
493 GetChild (rDescriptor
, maVisibleChildren
.size()-1);
495 // Inform listeners about new child.
497 aNewShape
<<= rDescriptor
.mxAccessibleShape
;
499 mrContext
.CommitChange (
500 AccessibleEventId::CHILD
,
503 RegisterAsDisposeListener(rxShape
);
512 void ChildrenManagerImpl::RemoveShape (const Reference
<drawing::XShape
>& rxShape
)
518 // Search shape in list of visible children.
519 ChildDescriptorListType::iterator
I (
520 ::std::find (maVisibleChildren
.begin(), maVisibleChildren
.end(),
521 ChildDescriptor (rxShape
)));
522 if (I
!= maVisibleChildren
.end())
524 // Remove descriptor from that list.
525 Reference
<XAccessible
> xAccessibleShape (I
->mxAccessibleShape
);
527 UnregisterAsDisposeListener (I
->mxShape
);
528 // Dispose the accessible object.
529 I
->disposeAccessibleObject (mrContext
);
531 // Now we can safely remove the child descriptor and thus
532 // invalidate the iterator.
533 maVisibleChildren
.erase (I
);
535 adjustIndexInParentOfShapes(maVisibleChildren
);
543 void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference
<
544 ::com::sun::star::drawing::XShapes
>& xShapeList
)
546 mxShapeList
= xShapeList
;
552 void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference
<css::accessibility::XAccessible
> const & shape
)
555 maAccessibleShapes
.push_back (shape
);
561 void ChildrenManagerImpl::ClearAccessibleShapeList()
563 // Copy the list of (visible) shapes to local lists and clear the
565 ChildDescriptorListType aLocalVisibleChildren
;
566 aLocalVisibleChildren
.swap(maVisibleChildren
);
567 AccessibleShapeList aLocalAccessibleShapes
;
568 aLocalAccessibleShapes
.swap(maAccessibleShapes
);
570 // Tell the listeners that all children are gone.
571 mrContext
.CommitChange (
572 AccessibleEventId::INVALIDATE_ALL_CHILDREN
,
576 // There are no accessible shapes left so the index assigned to new
577 // accessible shapes can be reset.
580 // Now the objects in the local lists can be safely disposed without
581 // having problems with callers that want to update their child lists.
583 // Clear the list of visible accessible objects. Objects not created on
584 // demand for XShapes are treated below.
585 ChildDescriptorListType::iterator I
,aEnd
= aLocalVisibleChildren
.end();
586 for (I
=aLocalVisibleChildren
.begin(); I
!= aEnd
; ++I
)
587 if ( I
->mxAccessibleShape
.is() && I
->mxShape
.is() )
589 ::comphelper::disposeComponent(I
->mxAccessibleShape
);
590 I
->mxAccessibleShape
= NULL
;
593 // Dispose all objects in the accessible shape list.
594 AccessibleShapeList::iterator J
,aEnd2
= aLocalAccessibleShapes
.end();
595 for (J
=aLocalAccessibleShapes
.begin(); J
!= aEnd2
; ++J
)
598 // Dispose the object.
599 ::comphelper::disposeComponent(*J
);
607 /** If the broadcasters change at which this object is registered then
608 unregister at old and register at new broadcasters.
610 void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
612 // Remember the current broadcasters and exchange the shape tree info.
613 Reference
<document::XEventBroadcaster
> xCurrentBroadcaster
;
614 Reference
<frame::XController
> xCurrentController
;
615 Reference
<view::XSelectionSupplier
> xCurrentSelectionSupplier
;
618 xCurrentBroadcaster
= maShapeTreeInfo
.GetModelBroadcaster();
619 xCurrentController
= maShapeTreeInfo
.GetController();
620 xCurrentSelectionSupplier
= Reference
<view::XSelectionSupplier
> (
621 xCurrentController
, uno::UNO_QUERY
);
622 maShapeTreeInfo
= rShapeTreeInfo
;
625 // Move registration to new model.
626 if (maShapeTreeInfo
.GetModelBroadcaster() != xCurrentBroadcaster
)
628 // Register at new broadcaster.
629 if (maShapeTreeInfo
.GetModelBroadcaster().is())
630 maShapeTreeInfo
.GetModelBroadcaster()->addEventListener (
631 static_cast<document::XEventListener
*>(this));
633 // Unregister at old broadcaster.
634 if (xCurrentBroadcaster
.is())
635 xCurrentBroadcaster
->removeEventListener (
636 static_cast<document::XEventListener
*>(this));
639 // Move registration to new selection supplier.
640 Reference
<frame::XController
> xNewController(maShapeTreeInfo
.GetController());
641 Reference
<view::XSelectionSupplier
> xNewSelectionSupplier (
642 xNewController
, uno::UNO_QUERY
);
643 if (xNewSelectionSupplier
!= xCurrentSelectionSupplier
)
645 // Register at new broadcaster.
646 if (xNewSelectionSupplier
.is())
648 xNewController
->addEventListener(
649 static_cast<document::XEventListener
*>(this));
651 xNewSelectionSupplier
->addSelectionChangeListener (
652 static_cast<view::XSelectionChangeListener
*>(this));
655 // Unregister at old broadcaster.
656 if (xCurrentSelectionSupplier
.is())
658 xCurrentSelectionSupplier
->removeSelectionChangeListener (
659 static_cast<view::XSelectionChangeListener
*>(this));
661 xCurrentController
->removeEventListener(
662 static_cast<document::XEventListener
*>(this));
667 // lang::XEventListener
669 ChildrenManagerImpl::disposing (const lang::EventObject
& rEventObject
)
670 throw (uno::RuntimeException
, std::exception
)
672 if (rEventObject
.Source
== maShapeTreeInfo
.GetModelBroadcaster()
673 || rEventObject
.Source
== maShapeTreeInfo
.GetController())
678 // Handle disposing UNO shapes.
681 Reference
<drawing::XShape
> xShape (rEventObject
.Source
, uno::UNO_QUERY
);
683 // Find the descriptor for the given shape.
684 ChildDescriptorListType::iterator
I (
685 ::std::find (maVisibleChildren
.begin(), maVisibleChildren
.end(),
686 ChildDescriptor (xShape
)));
687 if (I
!= maVisibleChildren
.end())
689 // Clear the descriptor.
690 I
->disposeAccessibleObject (mrContext
);
696 // document::XEventListener
697 /** Listen for new and removed shapes.
700 ChildrenManagerImpl::notifyEvent (
701 const document::EventObject
& rEventObject
)
702 throw (uno::RuntimeException
, std::exception
)
704 static const char sShapeInserted
[] = "ShapeInserted";
705 static const char sShapeRemoved
[] = "ShapeRemoved";
708 if (rEventObject
.EventName
== sShapeInserted
)
709 AddShape (Reference
<drawing::XShape
>(rEventObject
.Source
, uno::UNO_QUERY
));
710 else if (rEventObject
.EventName
== sShapeRemoved
)
711 RemoveShape (Reference
<drawing::XShape
>(rEventObject
.Source
, uno::UNO_QUERY
));
712 // else ignore unknown event.
715 // view::XSelectionChangeListener
717 ChildrenManagerImpl::selectionChanged (const lang::EventObject
& /*rEvent*/)
718 throw (uno::RuntimeException
, std::exception
)
726 void ChildrenManagerImpl::impl_dispose()
728 Reference
<frame::XController
> xController(maShapeTreeInfo
.GetController());
729 // Remove from broadcasters.
732 Reference
<view::XSelectionSupplier
> xSelectionSupplier (
733 xController
, uno::UNO_QUERY
);
734 if (xSelectionSupplier
.is())
736 xSelectionSupplier
->removeSelectionChangeListener (
737 static_cast<view::XSelectionChangeListener
*>(this));
740 catch( uno::RuntimeException
&)
745 if (xController
.is())
746 xController
->removeEventListener(
747 static_cast<document::XEventListener
*>(this));
749 catch( uno::RuntimeException
&)
752 maShapeTreeInfo
.SetController (NULL
);
756 // Remove from broadcaster.
757 if (maShapeTreeInfo
.GetModelBroadcaster().is())
758 maShapeTreeInfo
.GetModelBroadcaster()->removeEventListener (
759 static_cast<document::XEventListener
*>(this));
760 maShapeTreeInfo
.SetModelBroadcaster (NULL
);
762 catch( uno::RuntimeException
& )
765 ClearAccessibleShapeList ();
771 void SAL_CALL
ChildrenManagerImpl::disposing()
776 // IAccessibleViewForwarderListener
777 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType
,
778 const IAccessibleViewForwarder
* pViewForwarder
)
780 if (aChangeType
== IAccessibleViewForwarderListener::VISIBLE_AREA
)
785 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
786 for (I
=maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
788 AccessibleShape
* pShape
= I
->GetAccessibleShape();
790 pShape
->ViewForwarderChanged (aChangeType
, pViewForwarder
);
796 bool ChildrenManagerImpl::ReplaceChild (
797 AccessibleShape
* pCurrentChild
,
798 const ::com::sun::star::uno::Reference
< ::com::sun::star::drawing::XShape
>& _rxShape
,
800 const AccessibleShapeTreeInfo
& _rShapeTreeInfo
)
801 throw (uno::RuntimeException
)
803 AccessibleShapeInfo
aShapeInfo( _rxShape
, pCurrentChild
->getAccessibleParent(), this, _nIndex
);
804 // create the new child
805 AccessibleShape
* pNewChild
= ShapeTypeHandler::Instance().CreateAccessibleObject (
809 Reference
< XAccessible
> xNewChild( pNewChild
); // keep this alive (do this before calling Init!)
813 bool bResult
= false;
815 // Iterate over the visible children. If one of them has an already
816 // created accessible object that matches pCurrentChild then replace
817 // it. Otherwise the child to replace is either not in the list or has
818 // not ye been created (and is therefore not in the list, too) and a
819 // replacement is not necessary.
820 ChildDescriptorListType::iterator I
,aEnd
= maVisibleChildren
.end();
821 for (I
=maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
823 if (I
->GetAccessibleShape() == pCurrentChild
)
825 // Dispose the current child and send an event about its deletion.
826 pCurrentChild
->dispose();
827 mrContext
.CommitChange (
828 AccessibleEventId::CHILD
,
830 uno::makeAny (I
->mxAccessibleShape
));
832 // Replace with replacement and send an event about existence
834 I
->mxAccessibleShape
= pNewChild
;
835 mrContext
.CommitChange (
836 AccessibleEventId::CHILD
,
837 uno::makeAny (I
->mxAccessibleShape
),
844 // When not found among the visible children we have to search the list
845 // of accessible shapes. This is not yet implemented.
850 // Add the impl method for IAccessibleParent interface
851 AccessibleControlShape
* ChildrenManagerImpl::GetAccControlShapeFromModel(::com::sun::star::beans::XPropertySet
* pSet
) throw (::com::sun::star::uno::RuntimeException
)
853 sal_Int32 count
= GetChildCount();
854 for (sal_Int32 index
=0;index
<count
;index
++)
856 AccessibleShape
* pAccShape
= maVisibleChildren
[index
].GetAccessibleShape();
857 if (pAccShape
&& ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape
->GetXShape()) == DRAWING_CONTROL
)
859 ::accessibility::AccessibleControlShape
*pCtlAccShape
= static_cast < ::accessibility::AccessibleControlShape
* >(pAccShape
);
860 if (pCtlAccShape
&& pCtlAccShape
->GetControlModel() == pSet
)
866 uno::Reference
<XAccessible
>
867 ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference
<drawing::XShape
>& xShape
)
868 throw (uno::RuntimeException
)
870 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
871 for (I
= maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
873 if ( I
->mxShape
.get() == xShape
.get() )
874 return I
->mxAccessibleShape
;
876 return uno::Reference
<XAccessible
> ();
879 /** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
880 of all visible children. Maybe this should be changed to all children.
882 Iterate over all descriptors of visible accessible shapes and look them
885 If there is no valid controller then all shapes are deselected and
886 unfocused. If the controller's frame is not active then all shapes are
889 void ChildrenManagerImpl::UpdateSelection()
891 Reference
<frame::XController
> xController(maShapeTreeInfo
.GetController());
892 Reference
<view::XSelectionSupplier
> xSelectionSupplier (
893 xController
, uno::UNO_QUERY
);
895 // Try to cast the selection both to a multi selection and to a single
897 Reference
<container::XIndexAccess
> xSelectedShapeAccess
;
898 Reference
<drawing::XShape
> xSelectedShape
;
899 if (xSelectionSupplier
.is())
901 xSelectedShapeAccess
= Reference
<container::XIndexAccess
> (
902 xSelectionSupplier
->getSelection(), uno::UNO_QUERY
);
903 xSelectedShape
= Reference
<drawing::XShape
> (
904 xSelectionSupplier
->getSelection(), uno::UNO_QUERY
);
907 // Remember the current and new focused shape.
908 AccessibleShape
* pCurrentlyFocusedShape
= NULL
;
909 AccessibleShape
* pNewFocusedShape
= NULL
;
910 typedef std::pair
< AccessibleShape
* , sal_Bool
> PAIR_SHAPE
;//sal_Bool Selected,UnSelected.
911 typedef std::vector
< PAIR_SHAPE
> VEC_SHAPE
;
915 bool bHasSelectedShape
=false;
916 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
917 for (I
=maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
919 AccessibleShape
* pAccessibleShape
= I
->GetAccessibleShape();
920 if (I
->mxAccessibleShape
.is() && I
->mxShape
.is() && pAccessibleShape
!=NULL
)
922 short nRole
= pAccessibleShape
->getAccessibleRole();
924 nRole
== AccessibleRole::GRAPHIC
||
925 nRole
== AccessibleRole::EMBEDDED_OBJECT
||
926 nRole
== AccessibleRole::SHAPE
||
927 nRole
== AccessibleRole::IMAGE_MAP
||
928 nRole
== AccessibleRole::TABLE_CELL
||
929 nRole
== AccessibleRole::TABLE
);
930 bool bShapeIsSelected
= false;
932 // Look up the shape in the (single or multi-) selection.
933 if (xSelectedShape
.is())
935 if (I
->mxShape
== xSelectedShape
)
937 bShapeIsSelected
= true;
938 pNewFocusedShape
= pAccessibleShape
;
941 else if (xSelectedShapeAccess
.is())
943 sal_Int32 nCount
=xSelectedShapeAccess
->getCount();
944 for (sal_Int32 i
=0; i
<nCount
&&!bShapeIsSelected
; i
++)
945 if (xSelectedShapeAccess
->getByIndex(i
) == I
->mxShape
)
947 bShapeIsSelected
= true;
948 // In a multi-selection no shape has the focus.
950 pNewFocusedShape
= pAccessibleShape
;
954 // Set or reset the SELECTED state.
955 if (bShapeIsSelected
)
957 if (pAccessibleShape
->SetState (AccessibleStateType::SELECTED
))
961 vecSelect
.push_back(std::make_pair(pAccessibleShape
,sal_True
));
966 {//Selected not change,has selected shape before
967 bHasSelectedShape
=true;
971 //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
973 if(pAccessibleShape
->ResetState (AccessibleStateType::SELECTED
))
977 vecSelect
.push_back(std::make_pair(pAccessibleShape
,sal_False
));
982 // Does the shape have the current selection?
983 if (pAccessibleShape
->GetState (AccessibleStateType::FOCUSED
))
984 pCurrentlyFocusedShape
= pAccessibleShape
;
988 vcl::Window
*pParentWindow
= maShapeTreeInfo
.GetWindow();
989 bool bShapeActive
= false;
990 // For table cell, the table's parent must be checked to make sure it has focus.
993 vcl::Window
*pPWindow
= pParentWindow
->GetParent();
994 if (pParentWindow
->HasFocus() || (pPWindow
&& pPWindow
->HasFocus()))
997 // Move focus from current to newly focused shape.
998 if (pCurrentlyFocusedShape
!= pNewFocusedShape
)
1000 if (pCurrentlyFocusedShape
!= NULL
)
1001 pCurrentlyFocusedShape
->ResetState (AccessibleStateType::FOCUSED
);
1002 if (pNewFocusedShape
!= NULL
&& bShapeActive
)
1003 pNewFocusedShape
->SetState (AccessibleStateType::FOCUSED
);
1006 if (nAddSelect
>= 10 )//fire selection within
1008 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN
,uno::Any(),uno::Any());
1009 nAddSelect
=0 ;//not fire selection event
1011 //VEC_SHAPE::iterator vi = vecSelect.begin();
1012 //for (; vi != vecSelect.end() ;++vi)
1013 VEC_SHAPE::reverse_iterator vi
= vecSelect
.rbegin();
1014 for (; vi
!= vecSelect
.rend() ;++vi
)
1017 PAIR_SHAPE
&pairShape
= *vi
;
1018 Reference
< XAccessible
> xShape(pairShape
.first
);
1020 anyShape
<<= xShape
;
1022 if (pairShape
.second
)//Selection add
1024 if (bHasSelectedShape
)
1026 if ( nAddSelect
> 0 )
1028 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD
,anyShape
,uno::Any());
1033 //if has not selected shape ,first selected shape is fire selection event;
1034 if (nAddSelect
> 0 )
1036 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED
,anyShape
,uno::Any());
1038 if (nAddSelect
> 1 )//check other selected shape fire selection add event
1040 bHasSelectedShape
=true;
1044 else //selection remove
1046 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE
,anyShape
,uno::Any());
1050 // Remember whether there is a shape that now has the focus.
1051 mpFocusedShape
= pNewFocusedShape
;
1057 bool ChildrenManagerImpl::HasFocus()
1059 return mpFocusedShape
!= NULL
;
1065 void ChildrenManagerImpl::RemoveFocus()
1067 if (mpFocusedShape
!= NULL
)
1069 mpFocusedShape
->ResetState (AccessibleStateType::FOCUSED
);
1070 mpFocusedShape
= NULL
;
1076 void ChildrenManagerImpl::RegisterAsDisposeListener (
1077 const Reference
<drawing::XShape
>& xShape
)
1079 Reference
<lang::XComponent
> xComponent (xShape
, uno::UNO_QUERY
);
1080 if (xComponent
.is())
1081 xComponent
->addEventListener (
1082 static_cast<document::XEventListener
*>(this));
1088 void ChildrenManagerImpl::UnregisterAsDisposeListener (
1089 const Reference
<drawing::XShape
>& xShape
)
1091 Reference
<lang::XComponent
> xComponent (xShape
, uno::UNO_QUERY
);
1092 if (xComponent
.is())
1093 xComponent
->removeEventListener (
1094 static_cast<document::XEventListener
*>(this));
1097 // AccessibleChildDescriptor
1098 ChildDescriptor::ChildDescriptor (const Reference
<drawing::XShape
>& xShape
)
1100 mxAccessibleShape (NULL
),
1101 mbCreateEventPending (true)
1109 ChildDescriptor::ChildDescriptor (const Reference
<XAccessible
>& rxAccessibleShape
)
1111 mxAccessibleShape (rxAccessibleShape
),
1112 mbCreateEventPending (true)
1114 // Make sure that the accessible object has the <const>VISIBLE</const>
1116 AccessibleShape
* pAccessibleShape
= GetAccessibleShape();
1117 pAccessibleShape
->SetState (AccessibleStateType::VISIBLE
);
1123 ChildDescriptor::~ChildDescriptor()
1130 AccessibleShape
* ChildDescriptor::GetAccessibleShape() const
1132 return static_cast<AccessibleShape
*> (mxAccessibleShape
.get());
1135 void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex
)
1137 AccessibleShape
* pShape
= GetAccessibleShape();
1139 pShape
->setIndexInParent(_nIndex
);
1146 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase
& rParent
)
1148 if (mxAccessibleShape
.is())
1150 // Send event that the shape has been removed.
1152 aOldValue
<<= mxAccessibleShape
;
1153 rParent
.CommitChange (
1154 AccessibleEventId::CHILD
,
1158 // Dispose and remove the object.
1159 Reference
<lang::XComponent
> xComponent (mxAccessibleShape
, uno::UNO_QUERY
);
1160 if (xComponent
.is())
1161 xComponent
->dispose ();
1163 mxAccessibleShape
= NULL
;
1168 } // end of namespace accessibility
1170 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */