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 ===========================================
57 ChildrenManagerImpl::ChildrenManagerImpl (
58 const uno::Reference
<XAccessible
>& rxParent
,
59 const uno::Reference
<drawing::XShapes
>& rxShapeList
,
60 const AccessibleShapeTreeInfo
& rShapeTreeInfo
,
61 AccessibleContextBase
& rContext
)
62 : ::cppu::WeakComponentImplHelper2
<
63 ::com::sun::star::document::XEventListener
,
64 ::com::sun::star::view::XSelectionChangeListener
>(maMutex
),
65 mxShapeList (rxShapeList
),
67 maShapeTreeInfo (rShapeTreeInfo
),
77 ChildrenManagerImpl::~ChildrenManagerImpl (void)
79 DBG_ASSERT (rBHelper
.bDisposed
|| rBHelper
.bInDispose
,
80 "~AccessibleDrawDocumentView: object has not been disposed");
86 void ChildrenManagerImpl::Init (void)
88 // Register as view::XSelectionChangeListener.
89 Reference
<frame::XController
> xController(maShapeTreeInfo
.GetController());
90 Reference
<view::XSelectionSupplier
> xSelectionSupplier (
91 xController
, uno::UNO_QUERY
);
92 if (xSelectionSupplier
.is())
94 xController
->addEventListener(
95 static_cast<document::XEventListener
*>(this));
97 xSelectionSupplier
->addSelectionChangeListener (
98 static_cast<view::XSelectionChangeListener
*>(this));
101 // Register at model as document::XEventListener.
102 if (maShapeTreeInfo
.GetModelBroadcaster().is())
103 maShapeTreeInfo
.GetModelBroadcaster()->addEventListener (
104 static_cast<document::XEventListener
*>(this));
110 long ChildrenManagerImpl::GetChildCount (void) const throw ()
112 return maVisibleChildren
.size();
116 ::com::sun::star::uno::Reference
<
117 ::com::sun::star::drawing::XShape
> ChildrenManagerImpl::GetChildShape(long nIndex
)
118 throw (::com::sun::star::uno::RuntimeException
,
119 ::com::sun::star::lang::IndexOutOfBoundsException
)
121 uno::Reference
<XAccessible
> xAcc
= GetChild(nIndex
);
122 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
123 for (I
= maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
125 if (I
->mxAccessibleShape
== xAcc
)
128 return uno::Reference
< drawing::XShape
> ();
131 /** Return the requested accessible child object. Create it if it is not
134 uno::Reference
<XAccessible
>
135 ChildrenManagerImpl::GetChild (long nIndex
)
136 throw (::com::sun::star::uno::RuntimeException
,
137 ::com::sun::star::lang::IndexOutOfBoundsException
)
139 // Check whether the given index is valid.
140 if (nIndex
< 0 || (unsigned long)nIndex
>= maVisibleChildren
.size())
141 throw lang::IndexOutOfBoundsException (
142 "no accessible child with index " + OUString::number(nIndex
),
145 return GetChild (maVisibleChildren
[nIndex
],nIndex
);
151 /** Return the requested accessible child object. Create it if it is not
154 uno::Reference
<XAccessible
>
155 ChildrenManagerImpl::GetChild (ChildDescriptor
& rChildDescriptor
,sal_Int32 _nIndex
)
156 throw (::com::sun::star::uno::RuntimeException
)
158 if ( ! rChildDescriptor
.mxAccessibleShape
.is())
161 // Make sure that the requested accessible object has not been
162 // created while locking the global mutex.
163 if ( ! rChildDescriptor
.mxAccessibleShape
.is())
165 AccessibleShapeInfo
aShapeInfo(
166 rChildDescriptor
.mxShape
,
170 // Create accessible object that corresponds to the descriptor's
172 AccessibleShape
* pShape
=
173 ShapeTypeHandler::Instance().CreateAccessibleObject (
176 rChildDescriptor
.mxAccessibleShape
= uno::Reference
<XAccessible
> (
177 static_cast<uno::XWeak
*>(pShape
),
179 // Now that there is a reference to the new accessible shape we
180 // can safely call its Init() method.
181 if ( pShape
!= NULL
)
184 pShape
->setIndexInParent(_nIndex
);
189 return rChildDescriptor
.mxAccessibleShape
;
195 uno::Reference
<XAccessible
>
196 ChildrenManagerImpl::GetChild (const uno::Reference
<drawing::XShape
>& xShape
)
197 throw (uno::RuntimeException
)
199 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
200 for (I
= maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
202 if ( I
->mxShape
.get() == xShape
.get() )
203 return I
->mxAccessibleShape
;
205 return uno::Reference
<XAccessible
> ();
211 /** Find all shapes among the specified shapes that lie fully or partially
212 inside the visible area. Put those shapes into the cleared cache. The
213 corresponding accessible objects will be created on demand.
215 At the moment, first all accessible objects are removed from the cache
216 and the appropriate listeners are informed of this. Next, the list is
217 created again. This should be optimized in the future to not remove and
218 create objects that will be in the list before and after the update
221 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand
)
223 if (maShapeTreeInfo
.GetViewForwarder() == NULL
)
225 Rectangle aVisibleArea
= maShapeTreeInfo
.GetViewForwarder()->GetVisibleArea();
227 // 1. Create a local list of visible shapes.
228 ChildDescriptorListType aChildList
;
229 CreateListOfVisibleShapes (aChildList
);
231 // 2. Merge the information that is already known about the visible
232 // shapes from the current list into the new list.
233 MergeAccessibilityInformation (aChildList
);
235 // 3. Replace the current list of visible shapes with the new one. Do
236 // the same with the visible area.
239 adjustIndexInParentOfShapes(aChildList
);
241 // Use swap to copy the contents of the new list in constant time.
242 maVisibleChildren
.swap (aChildList
);
244 // aChildList now contains all the old children, while maVisibleChildren
245 // contains all the current children
247 // 4. Find all shapes in the old list that are not in the current list,
248 // send appropriate events and remove the accessible shape.
250 // Do this *after* we have set our new list of children, because
251 // removing a child may cause
253 // ChildDescriptor::disposeAccessibleObject -->
254 // AccessibleContextBase::CommitChange -->
255 // AtkListener::notifyEvent ->
256 // AtkListener::handleChildRemoved ->
257 // AtkListener::updateChildList
258 // AccessibleDrawDocumentView::getAccessibleChildCount ->
259 // ChildrenManagerImpl::GetChildCount ->
260 // maVisibleChildren.size()
262 // to be fired, and so the operations will take place on
263 // the list we are trying to replace
265 RemoveNonVisibleChildren (maVisibleChildren
, aChildList
);
269 maVisibleArea
= aVisibleArea
;
272 // 5. If the visible area has changed then send events that signal a
273 // change of their bounding boxes for all shapes that are members of
274 // both the current and the new list of visible shapes.
275 if (maVisibleArea
!= aVisibleArea
)
276 SendVisibleAreaEvents (maVisibleChildren
);
278 // 6. If children have to be created immediately and not on demand then
279 // create the missing accessible objects now.
280 if ( ! bCreateNewObjectsOnDemand
)
281 CreateAccessibilityObjects (maVisibleChildren
);
287 void ChildrenManagerImpl::CreateListOfVisibleShapes (
288 ChildDescriptorListType
& raDescriptorList
)
292 OSL_ASSERT (maShapeTreeInfo
.GetViewForwarder() != NULL
);
294 Rectangle aVisibleArea
= maShapeTreeInfo
.GetViewForwarder()->GetVisibleArea();
296 // Add the visible shapes for which the accessible objects already exist.
297 AccessibleShapeList::iterator I
,aEnd
= maAccessibleShapes
.end();
298 for (I
=maAccessibleShapes
.begin(); I
!= aEnd
; ++I
)
302 uno::Reference
<XAccessibleComponent
> xComponent (
303 (*I
)->getAccessibleContext(), uno::UNO_QUERY
);
306 // The bounding box of the object already is clipped to the
307 // visible area. The object is therefore visible if the
308 // bounding box has non-zero extensions.
309 awt::Rectangle
aPixelBBox (xComponent
->getBounds());
310 if ((aPixelBBox
.Width
> 0) && (aPixelBBox
.Height
> 0))
311 raDescriptorList
.push_back (ChildDescriptor (*I
));
316 // Add the visible shapes for which only the XShapes exist.
317 uno::Reference
<container::XIndexAccess
> xShapeAccess (mxShapeList
, uno::UNO_QUERY
);
318 if (xShapeAccess
.is())
320 sal_Int32 nShapeCount
= xShapeAccess
->getCount();
321 raDescriptorList
.reserve( nShapeCount
);
324 Rectangle aBoundingBox
;
325 uno::Reference
<drawing::XShape
> xShape
;
326 for (sal_Int32 i
=0; i
<nShapeCount
; ++i
)
328 xShapeAccess
->getByIndex(i
) >>= xShape
;
329 aPos
= xShape
->getPosition();
330 aSize
= xShape
->getSize();
332 aBoundingBox
.Left() = aPos
.X
;
333 aBoundingBox
.Top() = aPos
.Y
;
334 aBoundingBox
.Right() = aPos
.X
+ aSize
.Width
;
335 aBoundingBox
.Bottom() = aPos
.Y
+ aSize
.Height
;
337 // Insert shape if it is visible, i.e. its bounding box overlaps
339 if ( aBoundingBox
.IsOver (aVisibleArea
) )
340 raDescriptorList
.push_back (ChildDescriptor (xShape
));
348 void ChildrenManagerImpl::RemoveNonVisibleChildren (
349 const ChildDescriptorListType
& rNewChildList
,
350 ChildDescriptorListType
& rOldChildList
)
352 // Iterate over list of formerly visible children and remove those that
353 // are not visible anymore, i.e. member of the new list of visible
355 ChildDescriptorListType::iterator I
, aEnd
= rOldChildList
.end();
356 for (I
=rOldChildList
.begin(); I
!= aEnd
; ++I
)
358 if (::std::find(rNewChildList
.begin(), rNewChildList
.end(), *I
) == rNewChildList
.end())
360 // The child is disposed when there is a UNO shape from which
361 // the accessible shape can be created when the shape becomes
362 // visible again. When there is no such UNO shape then simply
363 // reset the descriptor but keep the accessibility object.
366 UnregisterAsDisposeListener (I
->mxShape
);
367 I
->disposeAccessibleObject (mrContext
);
371 AccessibleShape
* pAccessibleShape
= I
->GetAccessibleShape();
372 pAccessibleShape
->ResetState (AccessibleStateType::VISIBLE
);
373 I
->mxAccessibleShape
= NULL
;
382 void ChildrenManagerImpl::MergeAccessibilityInformation (
383 ChildDescriptorListType
& raNewChildList
)
385 ChildDescriptorListType::iterator aOldChildDescriptor
;
386 ChildDescriptorListType::iterator I
, aEnd
= raNewChildList
.end();
387 for (I
=raNewChildList
.begin(); I
!= aEnd
; ++I
)
389 aOldChildDescriptor
= ::std::find (maVisibleChildren
.begin(), maVisibleChildren
.end(), *I
);
391 // Copy accessible shape if that exists in the old descriptor.
392 bool bRegistrationIsNecessary
= true;
393 if (aOldChildDescriptor
!= maVisibleChildren
.end())
394 if (aOldChildDescriptor
->mxAccessibleShape
.is())
396 I
->mxAccessibleShape
= aOldChildDescriptor
->mxAccessibleShape
;
397 I
->mbCreateEventPending
= false;
398 bRegistrationIsNecessary
= false;
400 if (bRegistrationIsNecessary
)
401 RegisterAsDisposeListener (I
->mxShape
);
408 void ChildrenManagerImpl::SendVisibleAreaEvents (
409 ChildDescriptorListType
& raNewChildList
)
411 ChildDescriptorListType::iterator I
,aEnd
= raNewChildList
.end();
412 for (I
=raNewChildList
.begin(); I
!= aEnd
; ++I
)
414 // Tell shape of changed visible area. To do this, fake a
415 // change of the view forwarder. (Actually we usually get here
416 // as a result of a change of the view forwarder).
417 AccessibleShape
* pShape
= I
->GetAccessibleShape ();
419 pShape
->ViewForwarderChanged (
420 IAccessibleViewForwarderListener::VISIBLE_AREA
,
421 maShapeTreeInfo
.GetViewForwarder());
428 void ChildrenManagerImpl::CreateAccessibilityObjects (
429 ChildDescriptorListType
& raNewChildList
)
431 ChildDescriptorListType::iterator I
, aEnd
= raNewChildList
.end();
433 for ( I
= raNewChildList
.begin(); I
!= aEnd
; ++I
,++nPos
)
435 // Create the associated accessible object when the flag says so and
436 // it does not yet exist.
437 if ( ! I
->mxAccessibleShape
.is() )
439 if (I
->mxAccessibleShape
.is() && I
->mbCreateEventPending
)
441 I
->mbCreateEventPending
= false;
442 mrContext
.CommitChange (
443 AccessibleEventId::CHILD
,
444 uno::makeAny(I
->mxAccessibleShape
),
453 void ChildrenManagerImpl::AddShape (const Reference
<drawing::XShape
>& rxShape
)
457 SolarMutexClearableGuard aGuard
;
459 // Test visibility of the shape.
460 Rectangle aVisibleArea
= maShapeTreeInfo
.GetViewForwarder()->GetVisibleArea();
461 awt::Point aPos
= rxShape
->getPosition();
462 awt::Size aSize
= rxShape
->getSize();
464 Rectangle
aBoundingBox (
467 aPos
.X
+ aSize
.Width
,
468 aPos
.Y
+ aSize
.Height
);
470 // Add the shape only when it belongs to the list of shapes stored
471 // in mxShapeList (which is either a page or a group shape).
472 Reference
<container::XChild
> xChild (rxShape
, uno::UNO_QUERY
);
475 Reference
<drawing::XShapes
> xParent (xChild
->getParent(), uno::UNO_QUERY
);
476 if (xParent
== mxShapeList
)
477 if (aBoundingBox
.IsOver (aVisibleArea
))
479 // Add shape to list of visible shapes.
480 maVisibleChildren
.push_back (ChildDescriptor (rxShape
));
482 // Create accessibility object.
483 ChildDescriptor
& rDescriptor
= maVisibleChildren
.back();
484 GetChild (rDescriptor
, maVisibleChildren
.size()-1);
486 // Inform listeners about new child.
488 aNewShape
<<= rDescriptor
.mxAccessibleShape
;
490 mrContext
.CommitChange (
491 AccessibleEventId::CHILD
,
494 RegisterAsDisposeListener(rxShape
);
503 void ChildrenManagerImpl::RemoveShape (const Reference
<drawing::XShape
>& rxShape
)
509 // Search shape in list of visible children.
510 ChildDescriptorListType::iterator
I (
511 ::std::find (maVisibleChildren
.begin(), maVisibleChildren
.end(),
512 ChildDescriptor (rxShape
)));
513 if (I
!= maVisibleChildren
.end())
515 // Remove descriptor from that list.
516 Reference
<XAccessible
> xAccessibleShape (I
->mxAccessibleShape
);
518 UnregisterAsDisposeListener (I
->mxShape
);
519 // Dispose the accessible object.
520 I
->disposeAccessibleObject (mrContext
);
522 // Now we can safely remove the child descriptor and thus
523 // invalidate the iterator.
524 maVisibleChildren
.erase (I
);
526 adjustIndexInParentOfShapes(maVisibleChildren
);
534 void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference
<
535 ::com::sun::star::drawing::XShapes
>& xShapeList
)
537 mxShapeList
= xShapeList
;
543 void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference
<css::accessibility::XAccessible
> const & shape
)
546 maAccessibleShapes
.push_back (shape
);
552 void ChildrenManagerImpl::ClearAccessibleShapeList (void)
554 // Copy the list of (visible) shapes to local lists and clear the
556 ChildDescriptorListType aLocalVisibleChildren
;
557 aLocalVisibleChildren
.swap(maVisibleChildren
);
558 AccessibleShapeList aLocalAccessibleShapes
;
559 aLocalAccessibleShapes
.swap(maAccessibleShapes
);
561 // Tell the listeners that all children are gone.
562 mrContext
.CommitChange (
563 AccessibleEventId::INVALIDATE_ALL_CHILDREN
,
567 // There are no accessible shapes left so the index assigned to new
568 // accessible shapes can be reset.
571 // Now the objects in the local lists can be safely disposed without
572 // having problems with callers that want to update their child lists.
574 // Clear the list of visible accessible objects. Objects not created on
575 // demand for XShapes are treated below.
576 ChildDescriptorListType::iterator I
,aEnd
= aLocalVisibleChildren
.end();
577 for (I
=aLocalVisibleChildren
.begin(); I
!= aEnd
; ++I
)
578 if ( I
->mxAccessibleShape
.is() && I
->mxShape
.is() )
580 ::comphelper::disposeComponent(I
->mxAccessibleShape
);
581 I
->mxAccessibleShape
= NULL
;
584 // Dispose all objects in the accessible shape list.
585 AccessibleShapeList::iterator J
,aEnd2
= aLocalAccessibleShapes
.end();
586 for (J
=aLocalAccessibleShapes
.begin(); J
!= aEnd2
; ++J
)
589 // Dispose the object.
590 ::comphelper::disposeComponent(*J
);
598 /** If the broadcasters change at which this object is registered then
599 unregister at old and register at new broadcasters.
601 void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo
& rShapeTreeInfo
)
603 // Remember the current broadcasters and exchange the shape tree info.
604 Reference
<document::XEventBroadcaster
> xCurrentBroadcaster
;
605 Reference
<frame::XController
> xCurrentController
;
606 Reference
<view::XSelectionSupplier
> xCurrentSelectionSupplier
;
609 xCurrentBroadcaster
= maShapeTreeInfo
.GetModelBroadcaster();
610 xCurrentController
= maShapeTreeInfo
.GetController();
611 xCurrentSelectionSupplier
= Reference
<view::XSelectionSupplier
> (
612 xCurrentController
, uno::UNO_QUERY
);
613 maShapeTreeInfo
= rShapeTreeInfo
;
616 // Move registration to new model.
617 if (maShapeTreeInfo
.GetModelBroadcaster() != xCurrentBroadcaster
)
619 // Register at new broadcaster.
620 if (maShapeTreeInfo
.GetModelBroadcaster().is())
621 maShapeTreeInfo
.GetModelBroadcaster()->addEventListener (
622 static_cast<document::XEventListener
*>(this));
624 // Unregister at old broadcaster.
625 if (xCurrentBroadcaster
.is())
626 xCurrentBroadcaster
->removeEventListener (
627 static_cast<document::XEventListener
*>(this));
630 // Move registration to new selection supplier.
631 Reference
<frame::XController
> xNewController(maShapeTreeInfo
.GetController());
632 Reference
<view::XSelectionSupplier
> xNewSelectionSupplier (
633 xNewController
, uno::UNO_QUERY
);
634 if (xNewSelectionSupplier
!= xCurrentSelectionSupplier
)
636 // Register at new broadcaster.
637 if (xNewSelectionSupplier
.is())
639 xNewController
->addEventListener(
640 static_cast<document::XEventListener
*>(this));
642 xNewSelectionSupplier
->addSelectionChangeListener (
643 static_cast<view::XSelectionChangeListener
*>(this));
646 // Unregister at old broadcaster.
647 if (xCurrentSelectionSupplier
.is())
649 xCurrentSelectionSupplier
->removeSelectionChangeListener (
650 static_cast<view::XSelectionChangeListener
*>(this));
652 xCurrentController
->removeEventListener(
653 static_cast<document::XEventListener
*>(this));
661 //===== lang::XEventListener ================================================
664 ChildrenManagerImpl::disposing (const lang::EventObject
& rEventObject
)
665 throw (uno::RuntimeException
, std::exception
)
667 if (rEventObject
.Source
== maShapeTreeInfo
.GetModelBroadcaster()
668 || rEventObject
.Source
== maShapeTreeInfo
.GetController())
673 // Handle disposing UNO shapes.
676 Reference
<drawing::XShape
> xShape (rEventObject
.Source
, uno::UNO_QUERY
);
678 // Find the descriptor for the given shape.
679 ChildDescriptorListType::iterator
I (
680 ::std::find (maVisibleChildren
.begin(), maVisibleChildren
.end(),
681 ChildDescriptor (xShape
)));
682 if (I
!= maVisibleChildren
.end())
684 // Clear the descriptor.
685 I
->disposeAccessibleObject (mrContext
);
694 //===== document::XEventListener ============================================
696 /** Listen for new and removed shapes.
699 ChildrenManagerImpl::notifyEvent (
700 const document::EventObject
& rEventObject
)
701 throw (uno::RuntimeException
, std::exception
)
703 static const OUString
sShapeInserted ("ShapeInserted");
704 static const OUString
sShapeRemoved ("ShapeRemoved");
707 if (rEventObject
.EventName
== sShapeInserted
)
708 AddShape (Reference
<drawing::XShape
>(rEventObject
.Source
, uno::UNO_QUERY
));
709 else if (rEventObject
.EventName
== sShapeRemoved
)
710 RemoveShape (Reference
<drawing::XShape
>(rEventObject
.Source
, uno::UNO_QUERY
));
711 // else ignore unknown event.
717 //===== view::XSelectionChangeListener ======================================
720 ChildrenManagerImpl::selectionChanged (const lang::EventObject
& /*rEvent*/)
721 throw (uno::RuntimeException
, std::exception
)
729 void ChildrenManagerImpl::impl_dispose (void)
731 Reference
<frame::XController
> xController(maShapeTreeInfo
.GetController());
732 // Remove from broadcasters.
735 Reference
<view::XSelectionSupplier
> xSelectionSupplier (
736 xController
, uno::UNO_QUERY
);
737 if (xSelectionSupplier
.is())
739 xSelectionSupplier
->removeSelectionChangeListener (
740 static_cast<view::XSelectionChangeListener
*>(this));
743 catch( uno::RuntimeException
&)
748 if (xController
.is())
749 xController
->removeEventListener(
750 static_cast<document::XEventListener
*>(this));
752 catch( uno::RuntimeException
&)
755 maShapeTreeInfo
.SetController (NULL
);
759 // Remove from broadcaster.
760 if (maShapeTreeInfo
.GetModelBroadcaster().is())
761 maShapeTreeInfo
.GetModelBroadcaster()->removeEventListener (
762 static_cast<document::XEventListener
*>(this));
763 maShapeTreeInfo
.SetModelBroadcaster (NULL
);
765 catch( uno::RuntimeException
& )
768 ClearAccessibleShapeList ();
774 void SAL_CALL
ChildrenManagerImpl::disposing (void)
779 //===== IAccessibleViewForwarderListener ====================================
781 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType
,
782 const IAccessibleViewForwarder
* pViewForwarder
)
784 if (aChangeType
== IAccessibleViewForwarderListener::VISIBLE_AREA
)
789 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
790 for (I
=maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
792 AccessibleShape
* pShape
= I
->GetAccessibleShape();
794 pShape
->ViewForwarderChanged (aChangeType
, pViewForwarder
);
802 //===== IAccessibleParent ===================================================
804 bool ChildrenManagerImpl::ReplaceChild (
805 AccessibleShape
* pCurrentChild
,
806 const ::com::sun::star::uno::Reference
< ::com::sun::star::drawing::XShape
>& _rxShape
,
808 const AccessibleShapeTreeInfo
& _rShapeTreeInfo
)
809 throw (uno::RuntimeException
)
811 AccessibleShapeInfo
aShapeInfo( _rxShape
, pCurrentChild
->getAccessibleParent(), this, _nIndex
);
812 // create the new child
813 AccessibleShape
* pNewChild
= ShapeTypeHandler::Instance().CreateAccessibleObject (
817 Reference
< XAccessible
> xNewChild( pNewChild
); // keep this alive (do this before calling Init!)
821 bool bResult
= false;
823 // Iterate over the visible children. If one of them has an already
824 // created accessible object that matches pCurrentChild then replace
825 // it. Otherwise the child to replace is either not in the list or has
826 // not ye been created (and is therefore not in the list, too) and a
827 // replacement is not necessary.
828 ChildDescriptorListType::iterator I
,aEnd
= maVisibleChildren
.end();
829 for (I
=maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
831 if (I
->GetAccessibleShape() == pCurrentChild
)
833 // Dispose the current child and send an event about its deletion.
834 pCurrentChild
->dispose();
835 mrContext
.CommitChange (
836 AccessibleEventId::CHILD
,
838 uno::makeAny (I
->mxAccessibleShape
));
840 // Replace with replacement and send an event about existence
842 I
->mxAccessibleShape
= pNewChild
;
843 mrContext
.CommitChange (
844 AccessibleEventId::CHILD
,
845 uno::makeAny (I
->mxAccessibleShape
),
852 // When not found among the visible children we have to search the list
853 // of accessible shapes. This is not yet implemented.
858 // Add the impl method for IAccessibleParent interface
859 AccessibleControlShape
* ChildrenManagerImpl::GetAccControlShapeFromModel(::com::sun::star::beans::XPropertySet
* pSet
) throw (::com::sun::star::uno::RuntimeException
)
861 sal_Int32 count
= GetChildCount();
862 for (sal_Int32 index
=0;index
<count
;index
++)
864 AccessibleShape
* pAccShape
= maVisibleChildren
[index
].GetAccessibleShape();
865 if (pAccShape
&& ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape
->GetXShape()) == DRAWING_CONTROL
)
867 ::accessibility::AccessibleControlShape
*pCtlAccShape
= static_cast < ::accessibility::AccessibleControlShape
* >(pAccShape
);
868 if (pCtlAccShape
&& pCtlAccShape
->GetControlModel() == pSet
)
874 uno::Reference
<XAccessible
>
875 ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference
<drawing::XShape
>& xShape
)
876 throw (uno::RuntimeException
)
878 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
879 for (I
= maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
881 if ( I
->mxShape
.get() == xShape
.get() )
882 return I
->mxAccessibleShape
;
884 return uno::Reference
<XAccessible
> ();
887 /** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
888 of all visible children. Maybe this should be changed to all children.
890 Iterate over all descriptors of visible accessible shapes and look them
893 If there is no valid controller then all shapes are deselected and
894 unfocused. If the controller's frame is not active then all shapes are
897 void ChildrenManagerImpl::UpdateSelection (void)
899 Reference
<frame::XController
> xController(maShapeTreeInfo
.GetController());
900 Reference
<view::XSelectionSupplier
> xSelectionSupplier (
901 xController
, uno::UNO_QUERY
);
903 // Try to cast the selection both to a multi selection and to a single
905 Reference
<container::XIndexAccess
> xSelectedShapeAccess
;
906 Reference
<drawing::XShape
> xSelectedShape
;
907 if (xSelectionSupplier
.is())
909 xSelectedShapeAccess
= Reference
<container::XIndexAccess
> (
910 xSelectionSupplier
->getSelection(), uno::UNO_QUERY
);
911 xSelectedShape
= Reference
<drawing::XShape
> (
912 xSelectionSupplier
->getSelection(), uno::UNO_QUERY
);
915 // Remember the current and new focused shape.
916 AccessibleShape
* pCurrentlyFocusedShape
= NULL
;
917 AccessibleShape
* pNewFocusedShape
= NULL
;
918 typedef std::pair
< AccessibleShape
* , sal_Bool
> PAIR_SHAPE
;//sal_Bool Selected,UnSelected.
919 typedef std::vector
< PAIR_SHAPE
> VEC_SHAPE
;
923 bool bHasSelectedShape
=false;
924 ChildDescriptorListType::iterator I
, aEnd
= maVisibleChildren
.end();
925 for (I
=maVisibleChildren
.begin(); I
!= aEnd
; ++I
)
927 AccessibleShape
* pAccessibleShape
= I
->GetAccessibleShape();
928 if (I
->mxAccessibleShape
.is() && I
->mxShape
.is() && pAccessibleShape
!=NULL
)
930 short nRole
= pAccessibleShape
->getAccessibleRole();
932 nRole
== AccessibleRole::GRAPHIC
||
933 nRole
== AccessibleRole::EMBEDDED_OBJECT
||
934 nRole
== AccessibleRole::SHAPE
||
935 nRole
== AccessibleRole::IMAGE_MAP
||
936 nRole
== AccessibleRole::TABLE_CELL
||
937 nRole
== AccessibleRole::TABLE
);
938 bool bShapeIsSelected
= false;
940 // Look up the shape in the (single or multi-) selection.
941 if (xSelectedShape
.is())
943 if (I
->mxShape
== xSelectedShape
)
945 bShapeIsSelected
= true;
946 pNewFocusedShape
= pAccessibleShape
;
949 else if (xSelectedShapeAccess
.is())
951 sal_Int32 nCount
=xSelectedShapeAccess
->getCount();
952 for (sal_Int32 i
=0; i
<nCount
&&!bShapeIsSelected
; i
++)
953 if (xSelectedShapeAccess
->getByIndex(i
) == I
->mxShape
)
955 bShapeIsSelected
= true;
956 // In a multi-selection no shape has the focus.
958 pNewFocusedShape
= pAccessibleShape
;
962 // Set or reset the SELECTED state.
963 if (bShapeIsSelected
)
965 if (pAccessibleShape
->SetState (AccessibleStateType::SELECTED
))
969 vecSelect
.push_back(std::make_pair(pAccessibleShape
,sal_True
));
974 {//Selected not change,has selected shape before
975 bHasSelectedShape
=true;
979 //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
981 if(pAccessibleShape
->ResetState (AccessibleStateType::SELECTED
))
985 vecSelect
.push_back(std::make_pair(pAccessibleShape
,sal_False
));
990 // Does the shape have the current selection?
991 if (pAccessibleShape
->GetState (AccessibleStateType::FOCUSED
))
992 pCurrentlyFocusedShape
= pAccessibleShape
;
996 Window
*pParentWindow
= maShapeTreeInfo
.GetWindow();
997 bool bShapeActive
= false;
998 // For table cell, the table's parent must be checked to make sure it has focus.
1001 Window
*pPWindow
= pParentWindow
->GetParent();
1002 if (pParentWindow
->HasFocus() || (pPWindow
&& pPWindow
->HasFocus()))
1005 // Move focus from current to newly focused shape.
1006 if (pCurrentlyFocusedShape
!= pNewFocusedShape
)
1008 if (pCurrentlyFocusedShape
!= NULL
)
1009 pCurrentlyFocusedShape
->ResetState (AccessibleStateType::FOCUSED
);
1010 if (pNewFocusedShape
!= NULL
&& bShapeActive
)
1011 pNewFocusedShape
->SetState (AccessibleStateType::FOCUSED
);
1014 if (nAddSelect
>= 10 )//fire selection within
1016 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN
,uno::Any(),uno::Any());
1017 nAddSelect
=0 ;//not fire selection event
1019 //VEC_SHAPE::iterator vi = vecSelect.begin();
1020 //for (; vi != vecSelect.end() ;++vi)
1021 VEC_SHAPE::reverse_iterator vi
= vecSelect
.rbegin();
1022 for (; vi
!= vecSelect
.rend() ;++vi
)
1025 PAIR_SHAPE
&pairShape
= *vi
;
1026 Reference
< XAccessible
> xShape(pairShape
.first
);
1028 anyShape
<<= xShape
;
1030 if (pairShape
.second
)//Selection add
1032 if (bHasSelectedShape
)
1034 if ( nAddSelect
> 0 )
1036 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD
,anyShape
,uno::Any());
1041 //if has not selected shape ,first selected shape is fire selection event;
1042 if (nAddSelect
> 0 )
1044 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED
,anyShape
,uno::Any());
1046 if (nAddSelect
> 1 )//check other selected shape fire selection add event
1048 bHasSelectedShape
=true;
1052 else //selection remove
1054 mrContext
.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE
,anyShape
,uno::Any());
1058 // Remember whether there is a shape that now has the focus.
1059 mpFocusedShape
= pNewFocusedShape
;
1065 bool ChildrenManagerImpl::HasFocus (void)
1067 return mpFocusedShape
!= NULL
;
1073 void ChildrenManagerImpl::RemoveFocus (void)
1075 if (mpFocusedShape
!= NULL
)
1077 mpFocusedShape
->ResetState (AccessibleStateType::FOCUSED
);
1078 mpFocusedShape
= NULL
;
1084 void ChildrenManagerImpl::RegisterAsDisposeListener (
1085 const Reference
<drawing::XShape
>& xShape
)
1087 Reference
<lang::XComponent
> xComponent (xShape
, uno::UNO_QUERY
);
1088 if (xComponent
.is())
1089 xComponent
->addEventListener (
1090 static_cast<document::XEventListener
*>(this));
1096 void ChildrenManagerImpl::UnregisterAsDisposeListener (
1097 const Reference
<drawing::XShape
>& xShape
)
1099 Reference
<lang::XComponent
> xComponent (xShape
, uno::UNO_QUERY
);
1100 if (xComponent
.is())
1101 xComponent
->removeEventListener (
1102 static_cast<document::XEventListener
*>(this));
1108 //===== AccessibleChildDescriptor ===========================================
1110 ChildDescriptor::ChildDescriptor (const Reference
<drawing::XShape
>& xShape
)
1112 mxAccessibleShape (NULL
),
1113 mbCreateEventPending (true)
1121 ChildDescriptor::ChildDescriptor (const Reference
<XAccessible
>& rxAccessibleShape
)
1123 mxAccessibleShape (rxAccessibleShape
),
1124 mbCreateEventPending (true)
1126 // Make sure that the accessible object has the <const>VISIBLE</const>
1128 AccessibleShape
* pAccessibleShape
= GetAccessibleShape();
1129 pAccessibleShape
->SetState (AccessibleStateType::VISIBLE
);
1135 ChildDescriptor::~ChildDescriptor (void)
1142 AccessibleShape
* ChildDescriptor::GetAccessibleShape (void) const
1144 return static_cast<AccessibleShape
*> (mxAccessibleShape
.get());
1147 void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex
)
1149 AccessibleShape
* pShape
= GetAccessibleShape();
1151 pShape
->setIndexInParent(_nIndex
);
1158 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase
& rParent
)
1160 if (mxAccessibleShape
.is())
1162 // Send event that the shape has been removed.
1164 aOldValue
<<= mxAccessibleShape
;
1165 rParent
.CommitChange (
1166 AccessibleEventId::CHILD
,
1170 // Dispose and remove the object.
1171 Reference
<lang::XComponent
> xComponent (mxAccessibleShape
, uno::UNO_QUERY
);
1172 if (xComponent
.is())
1173 xComponent
->dispose ();
1175 mxAccessibleShape
= NULL
;
1180 } // end of namespace accessibility
1182 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */